hil_mlc.c

来自「linux 内核源代码」· C语言 代码 · 共 1,015 行 · 第 1/2 页

C
1,015
字号
	EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT,		    20000,	HILSEN_REPOLL,	HILSEN_DSR,	HILSEN_NEXT)	FUNC(hilse_dec_ddi, 0,	HILSEN_HEAL,	HILSEN_NEXT,	0)	/* 21 HILSEN_ACF */	FUNC(hilse_init_lcv, 0,	HILSEN_NEXT,	HILSEN_DOZE,	0)	/* 22 HILSEN_ACF2 */	FUNC(hilse_inc_lcv, 10,	HILSEN_NEXT,	HILSEN_START,	0)	OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1)	IN(20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_NEXT)	/* 25 HILSEN_DISC0 */	OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB)	EXPECT_DISC(HIL_PKT_CMD | HIL_CMD_ELB | HIL_ERR_INT,	       20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_DSR)	/* Only enter here if response just received */	/* 27 HILSEN_DISC */	OUT_DISC(HIL_PKT_CMD | HIL_CMD_IDD)	EXPECT_DISC(HIL_PKT_CMD | HIL_CMD_IDD | HIL_ERR_INT,	       20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_START)	FUNC(hilse_inc_ddi,  0,	HILSEN_NEXT,	HILSEN_START,	0)	FUNC(hilse_take_idd, 0,	HILSEN_MATCH,	HILSEN_IFCACF,	HILSEN_FOLLOW)	OUT_LAST(HIL_PKT_CMD | HIL_CMD_RSC)	EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_RSC | HIL_ERR_INT,	       30000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_DSR)	FUNC(hilse_take_rsc, 0,	HILSEN_MATCH,	0,		HILSEN_FOLLOW)	OUT_LAST(HIL_PKT_CMD | HIL_CMD_EXD)	EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_EXD | HIL_ERR_INT,	       30000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_DSR)	FUNC(hilse_take_exd, 0,	HILSEN_MATCH,	0,		HILSEN_FOLLOW)	OUT_LAST(HIL_PKT_CMD | HIL_CMD_RNM)	EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_RNM | HIL_ERR_INT,	       30000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_DSR)	FUNC(hilse_take_rnm, 0, HILSEN_MATCH,	0,		0)	/* 40 HILSEN_MATCH */	FUNC(hilse_match, 0,	HILSEN_NEXT,	HILSEN_NEXT,	/* TODO */ 0)	/* 41 HILSEN_OPERATE */	OUT(HIL_PKT_CMD | HIL_CMD_POL)	EXPECT(HIL_PKT_CMD | HIL_CMD_POL | HIL_ERR_INT,	       20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_NEXT)	FUNC(hilse_operate, 0,	HILSEN_OPERATE,	HILSEN_IFC,	HILSEN_NEXT)	/* 44 HILSEN_PROBE */	OUT_LAST(HIL_PKT_CMD | HIL_CMD_EPT)	IN(10000,		HILSEN_DISC,	HILSEN_DSR,	HILSEN_NEXT)	OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB)	IN(10000,		HILSEN_DISC,	HILSEN_DSR,	HILSEN_NEXT)	OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1)	IN(10000,		HILSEN_DISC0,	HILSEN_DSR,	HILSEN_NEXT)	OUT_LAST(HIL_PKT_CMD | HIL_CMD_ELB)	IN(10000,		HILSEN_OPERATE,	HILSEN_DSR,	HILSEN_DSR)	/* 52 HILSEN_DSR */	FUNC(hilse_set_ddi, -1,	HILSEN_NEXT,	0,		0)	OUT(HIL_PKT_CMD | HIL_CMD_DSR)	IN(20000,		HILSEN_DHR,	HILSEN_DHR,	HILSEN_IFC)	/* 55 HILSEN_REPOLL */	OUT(HIL_PKT_CMD | HIL_CMD_RPL)	EXPECT(HIL_PKT_CMD | HIL_CMD_RPL | HIL_ERR_INT,	       20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_NEXT)	FUNC(hilse_operate, 1,	HILSEN_OPERATE,	HILSEN_IFC,	HILSEN_PROBE)	/* 58 HILSEN_IFCACF */	OUT(HIL_PKT_CMD | HIL_CMD_IFC)	EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT,	       20000,		HILSEN_ACF2,	HILSEN_DHR2,	HILSEN_HEAL)	/* 60 HILSEN_END */};static inline void hilse_setup_input(hil_mlc *mlc, const struct hilse_node *node){	switch (node->act) {	case HILSE_EXPECT_DISC:		mlc->imatch = node->object.packet;		mlc->imatch |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT);		break;	case HILSE_EXPECT_LAST:		mlc->imatch = node->object.packet;		mlc->imatch |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT);		break;	case HILSE_EXPECT:		mlc->imatch = node->object.packet;		break;	case HILSE_IN:		mlc->imatch = 0;		break;	default:		BUG();	}	mlc->istarted = 1;	mlc->intimeout = node->arg;	do_gettimeofday(&(mlc->instart));	mlc->icount = 15;	memset(mlc->ipacket, 0, 16 * sizeof(hil_packet));	BUG_ON(down_trylock(&mlc->isem));}#ifdef HIL_MLC_DEBUGstatic int doze;static int seidx; /* For debug */#endifstatic int hilse_donode(hil_mlc *mlc){	const struct hilse_node *node;	int nextidx = 0;	int sched_long = 0;	unsigned long flags;#ifdef HIL_MLC_DEBUG	if (mlc->seidx && mlc->seidx != seidx &&	    mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) {		printk(KERN_DEBUG PREFIX "z%i \n {%i}", doze, mlc->seidx);		doze = 0;	}	seidx = mlc->seidx;#endif	node = hil_mlc_se + mlc->seidx;	switch (node->act) {		int rc;		hil_packet pack;	case HILSE_FUNC:		BUG_ON(node->object.func == NULL);		rc = node->object.func(mlc, node->arg);		nextidx = (rc > 0) ? node->ugly :			((rc < 0) ? node->bad : node->good);		if (nextidx == HILSEN_FOLLOW)			nextidx = rc;		break;	case HILSE_EXPECT_LAST:	case HILSE_EXPECT_DISC:	case HILSE_EXPECT:	case HILSE_IN:		/* Already set up from previous HILSE_OUT_* */		write_lock_irqsave(&mlc->lock, flags);		rc = mlc->in(mlc, node->arg);		if (rc == 2)  {			nextidx = HILSEN_DOZE;			sched_long = 1;			write_unlock_irqrestore(&mlc->lock, flags);			break;		}		if (rc == 1)			nextidx = node->ugly;		else if (rc == 0)			nextidx = node->good;		else			nextidx = node->bad;		mlc->istarted = 0;		write_unlock_irqrestore(&mlc->lock, flags);		break;	case HILSE_OUT_LAST:		write_lock_irqsave(&mlc->lock, flags);		pack = node->object.packet;		pack |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT);		goto out;	case HILSE_OUT_DISC:		write_lock_irqsave(&mlc->lock, flags);		pack = node->object.packet;		pack |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT);		goto out;	case HILSE_OUT:		write_lock_irqsave(&mlc->lock, flags);		pack = node->object.packet;	out:		if (mlc->istarted)			goto out2;		/* Prepare to receive input */		if ((node + 1)->act & HILSE_IN)			hilse_setup_input(mlc, node + 1);	out2:		write_unlock_irqrestore(&mlc->lock, flags);		if (down_trylock(&mlc->osem)) {			nextidx = HILSEN_DOZE;			break;		}		up(&mlc->osem);		write_lock_irqsave(&mlc->lock, flags);		if (!mlc->ostarted) {			mlc->ostarted = 1;			mlc->opacket = pack;			mlc->out(mlc);			nextidx = HILSEN_DOZE;			write_unlock_irqrestore(&mlc->lock, flags);			break;		}		mlc->ostarted = 0;		do_gettimeofday(&(mlc->instart));		write_unlock_irqrestore(&mlc->lock, flags);		nextidx = HILSEN_NEXT;		break;	case HILSE_CTS:		write_lock_irqsave(&mlc->lock, flags);		nextidx = mlc->cts(mlc) ? node->bad : node->good;		write_unlock_irqrestore(&mlc->lock, flags);		break;	default:		BUG();	}#ifdef HIL_MLC_DEBUG	if (nextidx == HILSEN_DOZE)		doze++;#endif	while (nextidx & HILSEN_SCHED) {		struct timeval tv;		if (!sched_long)			goto sched;		do_gettimeofday(&tv);		tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec);		tv.tv_usec -= mlc->instart.tv_usec;		if (tv.tv_usec >= mlc->intimeout) goto sched;		tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / USEC_PER_SEC;		if (!tv.tv_usec) goto sched;		mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec);		break;	sched:		tasklet_schedule(&hil_mlcs_tasklet);		break;	}	if (nextidx & HILSEN_DOWN)		mlc->seidx += nextidx & HILSEN_MASK;	else if (nextidx & HILSEN_UP)		mlc->seidx -= nextidx & HILSEN_MASK;	else		mlc->seidx = nextidx & HILSEN_MASK;	if (nextidx & HILSEN_BREAK)		return 1;	return 0;}/******************** tasklet context functions **************************/static void hil_mlcs_process(unsigned long unused){	struct list_head *tmp;	read_lock(&hil_mlcs_lock);	list_for_each(tmp, &hil_mlcs) {		struct hil_mlc *mlc = list_entry(tmp, hil_mlc, list);		while (hilse_donode(mlc) == 0) {#ifdef HIL_MLC_DEBUG			if (mlc->seidx != 41 &&			    mlc->seidx != 42 &&			    mlc->seidx != 43)				printk(KERN_DEBUG PREFIX " + ");#endif		}	}	read_unlock(&hil_mlcs_lock);}/************************* Keepalive timer task *********************/void hil_mlcs_timer(unsigned long data){	hil_mlcs_probe = 1;	tasklet_schedule(&hil_mlcs_tasklet);	/* Re-insert the periodic task. */	if (!timer_pending(&hil_mlcs_kicker))		mod_timer(&hil_mlcs_kicker, jiffies + HZ);}/******************** user/kernel context functions **********************/static int hil_mlc_serio_write(struct serio *serio, unsigned char c){	struct hil_mlc_serio_map *map;	struct hil_mlc *mlc;	struct serio_driver *drv;	uint8_t *idx, *last;	map = serio->port_data;	BUG_ON(map == NULL);	mlc = map->mlc;	BUG_ON(mlc == NULL);	mlc->serio_opacket[map->didx] |=		((hil_packet)c) << (8 * (3 - mlc->serio_oidx[map->didx]));	if (mlc->serio_oidx[map->didx] >= 3) {		/* for now only commands */		if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD))			return -EIO;		switch (mlc->serio_opacket[map->didx] & HIL_PKT_DATA_MASK) {		case HIL_CMD_IDD:			idx = mlc->di[map->didx].idd;			goto emu;		case HIL_CMD_RSC:			idx = mlc->di[map->didx].rsc;			goto emu;		case HIL_CMD_EXD:			idx = mlc->di[map->didx].exd;			goto emu;		case HIL_CMD_RNM:			idx = mlc->di[map->didx].rnm;			goto emu;		default:			break;		}		mlc->serio_oidx[map->didx] = 0;		mlc->serio_opacket[map->didx] = 0;	}	mlc->serio_oidx[map->didx]++;	return -EIO; emu:	drv = serio->drv;	BUG_ON(drv == NULL);	last = idx + 15;	while ((last != idx) && (*last == 0))		last--;	while (idx != last) {		drv->interrupt(serio, 0, 0);		drv->interrupt(serio, HIL_ERR_INT >> 16, 0);		drv->interrupt(serio, 0, 0);		drv->interrupt(serio, *idx, 0);		idx++;	}	drv->interrupt(serio, 0, 0);	drv->interrupt(serio, HIL_ERR_INT >> 16, 0);	drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);	drv->interrupt(serio, *idx, 0);	mlc->serio_oidx[map->didx] = 0;	mlc->serio_opacket[map->didx] = 0;	return 0;}static int hil_mlc_serio_open(struct serio *serio){	struct hil_mlc_serio_map *map;	struct hil_mlc *mlc;	if (serio_get_drvdata(serio) != NULL)		return -EBUSY;	map = serio->port_data;	BUG_ON(map == NULL);	mlc = map->mlc;	BUG_ON(mlc == NULL);	return 0;}static void hil_mlc_serio_close(struct serio *serio){	struct hil_mlc_serio_map *map;	struct hil_mlc *mlc;	map = serio->port_data;	BUG_ON(map == NULL);	mlc = map->mlc;	BUG_ON(mlc == NULL);	serio_set_drvdata(serio, NULL);	serio->drv = NULL;	/* TODO wake up interruptable */}static const struct serio_device_id hil_mlc_serio_id = {	.type = SERIO_HIL_MLC,	.proto = SERIO_HIL,	.extra = SERIO_ANY,	.id = SERIO_ANY,};int hil_mlc_register(hil_mlc *mlc){	int i;	unsigned long flags;	BUG_ON(mlc == NULL);	mlc->istarted = 0;	mlc->ostarted = 0;	rwlock_init(&mlc->lock);	init_MUTEX(&mlc->osem);	init_MUTEX(&mlc->isem);	mlc->icount = -1;	mlc->imatch = 0;	mlc->opercnt = 0;	init_MUTEX_LOCKED(&(mlc->csem));	hil_mlc_clear_di_scratch(mlc);	hil_mlc_clear_di_map(mlc, 0);	for (i = 0; i < HIL_MLC_DEVMEM; i++) {		struct serio *mlc_serio;		hil_mlc_copy_di_scratch(mlc, i);		mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL);		mlc->serio[i] = mlc_serio;		snprintf(mlc_serio->name, sizeof(mlc_serio->name)-1, "HIL_SERIO%d", i);		snprintf(mlc_serio->phys, sizeof(mlc_serio->phys)-1, "HIL%d", i);		mlc_serio->id			= hil_mlc_serio_id;		mlc_serio->write		= hil_mlc_serio_write;		mlc_serio->open			= hil_mlc_serio_open;		mlc_serio->close		= hil_mlc_serio_close;		mlc_serio->port_data		= &(mlc->serio_map[i]);		mlc->serio_map[i].mlc		= mlc;		mlc->serio_map[i].didx		= i;		mlc->serio_map[i].di_revmap	= -1;		mlc->serio_opacket[i]		= 0;		mlc->serio_oidx[i]		= 0;		serio_register_port(mlc_serio);	}	mlc->tasklet = &hil_mlcs_tasklet;	write_lock_irqsave(&hil_mlcs_lock, flags);	list_add_tail(&mlc->list, &hil_mlcs);	mlc->seidx = HILSEN_START;	write_unlock_irqrestore(&hil_mlcs_lock, flags);	tasklet_schedule(&hil_mlcs_tasklet);	return 0;}int hil_mlc_unregister(hil_mlc *mlc){	struct list_head *tmp;	unsigned long flags;	int i;	BUG_ON(mlc == NULL);	write_lock_irqsave(&hil_mlcs_lock, flags);	list_for_each(tmp, &hil_mlcs)		if (list_entry(tmp, hil_mlc, list) == mlc)			goto found;	/* not found in list */	write_unlock_irqrestore(&hil_mlcs_lock, flags);	tasklet_schedule(&hil_mlcs_tasklet);	return -ENODEV; found:	list_del(tmp);	write_unlock_irqrestore(&hil_mlcs_lock, flags);	for (i = 0; i < HIL_MLC_DEVMEM; i++) {		serio_unregister_port(mlc->serio[i]);		mlc->serio[i] = NULL;	}	tasklet_schedule(&hil_mlcs_tasklet);	return 0;}/**************************** Module interface *************************/static int __init hil_mlc_init(void){	init_timer(&hil_mlcs_kicker);	hil_mlcs_kicker.expires = jiffies + HZ;	hil_mlcs_kicker.function = &hil_mlcs_timer;	add_timer(&hil_mlcs_kicker);	tasklet_enable(&hil_mlcs_tasklet);	return 0;}static void __exit hil_mlc_exit(void){	del_timer(&hil_mlcs_kicker);	tasklet_disable(&hil_mlcs_tasklet);	tasklet_kill(&hil_mlcs_tasklet);}module_init(hil_mlc_init);module_exit(hil_mlc_exit);

⌨️ 快捷键说明

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