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

📄 pvrusb2-i2c-core.c

📁 V4l driver for DVB HD
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	mutex_lock(&hdw->i2c_list_lock); do {		pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN");		if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) {			/* One or more I2C clients have attached since we			   last synced.  So scan the list and identify the			   new clients. */			char *buf;			unsigned int cnt;			unsigned long amask = 0;			buf = kmalloc(BUFSIZE,GFP_KERNEL);			pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");			hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;			list_for_each(item,&hdw->i2c_clients) {				cp = list_entry(item,struct pvr2_i2c_client,						list);				if (!cp->detected_flag) {					cp->ctl_mask = 0;					pvr2_i2c_probe(hdw,cp);					cp->detected_flag = !0;					msk = cp->ctl_mask;					cnt = 0;					if (buf) {						cnt = pvr2_i2c_client_describe(							cp,							PVR2_I2C_DETAIL_ALL,							buf,BUFSIZE);					}					trace_i2c("Probed: %.*s",cnt,buf);					if (handler_check(cp)) {						hdw->i2c_pend_types |=							PVR2_I2C_PEND_CLIENT;					}					cp->pend_mask = msk;					hdw->i2c_pend_mask |= msk;					hdw->i2c_pend_types |=						PVR2_I2C_PEND_REFRESH;				}				amask |= cp->ctl_mask;			}			hdw->i2c_active_mask = amask;			if (buf) kfree(buf);		}		if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) {			/* Need to do one or more global updates.  Arrange			   for this to happen. */			unsigned long m2;			pvr2_trace(PVR2_TRACE_I2C_CORE,				   "i2c: PEND_STALE (0x%lx)",				   hdw->i2c_stale_mask);			hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;			list_for_each(item,&hdw->i2c_clients) {				cp = list_entry(item,struct pvr2_i2c_client,						list);				m2 = hdw->i2c_stale_mask;				m2 &= cp->ctl_mask;				m2 &= ~cp->pend_mask;				if (m2) {					pvr2_trace(PVR2_TRACE_I2C_CORE,						   "i2c: cp=%p setting 0x%lx",						   cp,m2);					cp->pend_mask |= m2;				}			}			hdw->i2c_pend_mask |= hdw->i2c_stale_mask;			hdw->i2c_stale_mask = 0;			hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH;		}		if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) {			/* One or more client handlers are asking for an			   update.  Run through the list of known clients			   and update each one. */			pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");			hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;			list_for_each_safe(item,nc,&hdw->i2c_clients) {				cp = list_entry(item,struct pvr2_i2c_client,						list);				if (!cp->handler) continue;				if (!cp->handler->func_table->update) continue;				pvr2_trace(PVR2_TRACE_I2C_CORE,					   "i2c: cp=%p update",cp);				mutex_unlock(&hdw->i2c_list_lock);				cp->handler->func_table->update(					cp->handler->func_data);				mutex_lock(&hdw->i2c_list_lock);				/* If client's update function set some				   additional pending bits, account for that				   here. */				if (cp->pend_mask & ~hdw->i2c_pend_mask) {					hdw->i2c_pend_mask |= cp->pend_mask;					hdw->i2c_pend_types |=						PVR2_I2C_PEND_REFRESH;				}			}		}		if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) {			const struct pvr2_i2c_op *opf;			unsigned long pm;			/* Some actual updates are pending.  Walk through			   each update type and perform it. */			pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH"				   " (0x%lx)",hdw->i2c_pend_mask);			hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH;			pm = hdw->i2c_pend_mask;			hdw->i2c_pend_mask = 0;			for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {				if (!(pm & msk)) continue;				pm &= ~msk;				list_for_each(item,&hdw->i2c_clients) {					cp = list_entry(item,							struct pvr2_i2c_client,							list);					if (cp->pend_mask & msk) {						cp->pend_mask &= ~msk;						cp->recv_enable = !0;					} else {						cp->recv_enable = 0;					}				}				opf = pvr2_i2c_get_op(idx);				if (!opf) continue;				mutex_unlock(&hdw->i2c_list_lock);				opf->update(hdw);				mutex_lock(&hdw->i2c_list_lock);			}		}		pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END");	} while (0); mutex_unlock(&hdw->i2c_list_lock);}int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw){	unsigned long msk,sm,pm;	unsigned int idx;	const struct pvr2_i2c_op *opf;	struct list_head *item;	struct pvr2_i2c_client *cp;	unsigned int pt = 0;	pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN");	pm = hdw->i2c_active_mask;	sm = 0;	for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {		if (!(msk & pm)) continue;		pm &= ~msk;		opf = pvr2_i2c_get_op(idx);		if (!opf) continue;		if (opf->check(hdw)) {			sm |= msk;		}	}	if (sm) pt |= PVR2_I2C_PEND_STALE;	list_for_each(item,&hdw->i2c_clients) {		cp = list_entry(item,struct pvr2_i2c_client,list);		if (!handler_check(cp)) continue;		pt |= PVR2_I2C_PEND_CLIENT;	}	if (pt) {		mutex_lock(&hdw->i2c_list_lock); do {			hdw->i2c_pend_types |= pt;			hdw->i2c_stale_mask |= sm;			hdw->i2c_pend_mask |= hdw->i2c_stale_mask;		} while (0); mutex_unlock(&hdw->i2c_list_lock);	}	pvr2_trace(PVR2_TRACE_I2C_CORE,		   "i2c: types=0x%x stale=0x%lx pend=0x%lx",		   hdw->i2c_pend_types,		   hdw->i2c_stale_mask,		   hdw->i2c_pend_mask);	pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END");	return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0;}unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,				      unsigned int detail,				      char *buf,unsigned int maxlen){	unsigned int ccnt,bcnt;	int spcfl = 0;	const struct pvr2_i2c_op *opf;	ccnt = 0;	if (detail & PVR2_I2C_DETAIL_DEBUG) {		bcnt = scnprintf(buf,maxlen,				 "ctxt=%p ctl_mask=0x%lx",				 cp,cp->ctl_mask);		ccnt += bcnt; buf += bcnt; maxlen -= bcnt;		spcfl = !0;	}	bcnt = scnprintf(buf,maxlen,			 "%s%s @ 0x%x",			 (spcfl ? " " : ""),			 cp->client->name,			 cp->client->addr);	ccnt += bcnt; buf += bcnt; maxlen -= bcnt;	if ((detail & PVR2_I2C_DETAIL_HANDLER) &&	    cp->handler && cp->handler->func_table->describe) {		bcnt = scnprintf(buf,maxlen," (");		ccnt += bcnt; buf += bcnt; maxlen -= bcnt;		bcnt = cp->handler->func_table->describe(			cp->handler->func_data,buf,maxlen);		ccnt += bcnt; buf += bcnt; maxlen -= bcnt;		bcnt = scnprintf(buf,maxlen,")");		ccnt += bcnt; buf += bcnt; maxlen -= bcnt;	}	if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) {		unsigned int idx;		unsigned long msk,sm;		int spcfl;		bcnt = scnprintf(buf,maxlen," [");		ccnt += bcnt; buf += bcnt; maxlen -= bcnt;		sm = 0;		spcfl = 0;		for (idx = 0, msk = 1; msk; idx++, msk <<= 1) {			if (!(cp->ctl_mask & msk)) continue;			opf = pvr2_i2c_get_op(idx);			if (opf) {				bcnt = scnprintf(buf,maxlen,"%s%s",						 spcfl ? " " : "",						 opf->name);				ccnt += bcnt; buf += bcnt; maxlen -= bcnt;				spcfl = !0;			} else {				sm |= msk;			}		}		if (sm) {			bcnt = scnprintf(buf,maxlen,"%s%lx",					 idx != 0 ? " " : "",sm);			ccnt += bcnt; buf += bcnt; maxlen -= bcnt;		}		bcnt = scnprintf(buf,maxlen,"]");		ccnt += bcnt; buf += bcnt; maxlen -= bcnt;	}	return ccnt;}unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,			     char *buf,unsigned int maxlen){	unsigned int ccnt,bcnt;	struct list_head *item;	struct pvr2_i2c_client *cp;	ccnt = 0;	mutex_lock(&hdw->i2c_list_lock); do {		list_for_each(item,&hdw->i2c_clients) {			cp = list_entry(item,struct pvr2_i2c_client,list);			bcnt = pvr2_i2c_client_describe(				cp,				(PVR2_I2C_DETAIL_HANDLER|				 PVR2_I2C_DETAIL_CTLMASK),				buf,maxlen);			ccnt += bcnt; buf += bcnt; maxlen -= bcnt;			bcnt = scnprintf(buf,maxlen,"\n");			ccnt += bcnt; buf += bcnt; maxlen -= bcnt;		}	} while (0); mutex_unlock(&hdw->i2c_list_lock);	return ccnt;}static int pvr2_i2c_attach_inform(struct i2c_client *client){	struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);	struct pvr2_i2c_client *cp;	int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);	cp = kmalloc(sizeof(*cp),GFP_KERNEL);	trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",		  client->name,		  client->addr,cp);	if (!cp) return -ENOMEM;	memset(cp,0,sizeof(*cp));	INIT_LIST_HEAD(&cp->list);	cp->client = client;	mutex_lock(&hdw->i2c_list_lock); do {		list_add_tail(&cp->list,&hdw->i2c_clients);		hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;	} while (0); mutex_unlock(&hdw->i2c_list_lock);	if (fl) pvr2_hdw_poll_trigger_unlocked(hdw);	return 0;}static int pvr2_i2c_detach_inform(struct i2c_client *client){	struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);	struct pvr2_i2c_client *cp;	struct list_head *item,*nc;	unsigned long amask = 0;	int foundfl = 0;	mutex_lock(&hdw->i2c_list_lock); do {		list_for_each_safe(item,nc,&hdw->i2c_clients) {			cp = list_entry(item,struct pvr2_i2c_client,list);			if (cp->client == client) {				trace_i2c("pvr2_i2c_detach"					  " [client=%s @ 0x%x ctxt=%p]",					  client->name,					  client->addr,cp);				if (cp->handler &&				    cp->handler->func_table->detach) {					cp->handler->func_table->detach(						cp->handler->func_data);				}				list_del(&cp->list);				kfree(cp);				foundfl = !0;				continue;			}			amask |= cp->ctl_mask;		}		hdw->i2c_active_mask = amask;	} while (0); mutex_unlock(&hdw->i2c_list_lock);	if (!foundfl) {		trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",			  client->name,			  client->addr);	}	return 0;}static struct i2c_algorithm pvr2_i2c_algo_template = {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)	.id            = I2C_HW_B_BT848,#endif	.master_xfer   = pvr2_i2c_xfer,	.algo_control  = pvr2_i2c_control,	.functionality = pvr2_i2c_functionality,};static struct i2c_adapter pvr2_i2c_adap_template = {	.owner         = THIS_MODULE,	.class	   = I2C_CLASS_TV_ANALOG,	.id            = I2C_HW_B_BT848,	.client_register = pvr2_i2c_attach_inform,	.client_unregister = pvr2_i2c_detach_inform,};static void do_i2c_scan(struct pvr2_hdw *hdw){	struct i2c_msg msg[1];	int i,rc;	msg[0].addr = 0;	msg[0].flags = I2C_M_RD;	msg[0].len = 0;	msg[0].buf = 0;	printk("%s: i2c scan beginning\n",hdw->name);	for (i = 0; i < 128; i++) {		msg[0].addr = i;		rc = i2c_transfer(&hdw->i2c_adap,msg,				  sizeof(msg)/sizeof(msg[0]));		if (rc != 1) continue;		printk("%s: i2c scan: found device @ 0x%x\n",hdw->name,i);	}	printk("%s: i2c scan done.\n",hdw->name);}void pvr2_i2c_core_init(struct pvr2_hdw *hdw){	memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));	memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo));	strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name));#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)	strlcpy(hdw->i2c_algo.name,hdw->name,sizeof(hdw->i2c_algo.name));#endif	hdw->i2c_adap.algo = &hdw->i2c_algo;	hdw->i2c_adap.algo_data = hdw;	hdw->i2c_pend_mask = 0;	hdw->i2c_stale_mask = 0;	hdw->i2c_active_mask = 0;	INIT_LIST_HEAD(&hdw->i2c_clients);	mutex_init(&hdw->i2c_list_lock);	hdw->i2c_linked = !0;	i2c_add_adapter(&hdw->i2c_adap);	if (i2c_scan) do_i2c_scan(hdw);}void pvr2_i2c_core_done(struct pvr2_hdw *hdw){	if (hdw->i2c_linked) {		i2c_del_adapter(&hdw->i2c_adap);		hdw->i2c_linked = 0;	}}/*  Stuff for Emacs to see, in order to encourage consistent editing style:  *** Local Variables: ***  *** mode: c ***  *** fill-column: 75 ***  *** tab-width: 8 ***  *** c-basic-offset: 8 ***  *** End: ***  */

⌨️ 快捷键说明

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