📄 hil_mlc.c
字号:
/* 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, 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)); if (down_trylock(&(mlc->isem))) BUG(); return;}#ifdef HIL_MLC_DEBUGstatic int doze = 0;static int seidx; /* For debug */static int kick = 1;#endifstatic int hilse_donode (hil_mlc *mlc) { 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%s {%i}", doze, kick ? "K" : "", mlc->seidx); doze = 0; } kick = 0; seidx = mlc->seidx;#endif node = hil_mlc_se + mlc->seidx; switch (node->act) { int rc; hil_packet pack; case HILSE_FUNC: if (node->object.func == NULL) break; 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: nextidx = mlc->cts(mlc) ? node->bad : node->good; break; default: BUG(); nextidx = 0; break; }#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 += 1000000 * (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 / 1000000; 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; if (map == NULL) { BUG(); return -EIO; } mlc = map->mlc; if (mlc == NULL) { BUG(); return -EIO; } 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; if (drv == NULL) { BUG(); return -EIO; } last = idx + 15; while ((last != idx) && (*last == 0)) last--; while (idx != last) { drv->interrupt(serio, 0, 0, NULL); drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL); drv->interrupt(serio, 0, 0, NULL); drv->interrupt(serio, *idx, 0, NULL); idx++; } drv->interrupt(serio, 0, 0, NULL); drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL); drv->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL); drv->interrupt(serio, *idx, 0, NULL); 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->private != NULL) return -EBUSY; map = serio->port_data; if (map == NULL) { BUG(); return -ENODEV; } mlc = map->mlc; if (mlc == NULL) { BUG(); return -ENODEV; } 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; if (map == NULL) { BUG(); return; } mlc = map->mlc; if (mlc == NULL) { BUG(); return; } serio->private = NULL; serio->drv = NULL; /* TODO wake up interruptable */}int hil_mlc_register(hil_mlc *mlc) { int i; unsigned long flags; if (mlc == NULL) { return -EINVAL; } 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 = kmalloc(sizeof(*mlc_serio), GFP_KERNEL); mlc->serio[i] = mlc_serio; memset(mlc_serio, 0, sizeof(*mlc_serio)); mlc_serio->type = SERIO_HIL | SERIO_HIL_MLC; 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; if (mlc == NULL) return -EINVAL; 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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -