📄 dtlk.c
字号:
TRACE_RET; dtlk_stop_timer(); return 0;}int __init dtlk_init(void){ dtlk_port_lpc = 0; dtlk_port_tts = 0; dtlk_busy = 0; dtlk_timer_active = 0; dtlk_major = register_chrdev(0, "dtlk", &dtlk_fops); if (dtlk_major == 0) { printk(KERN_ERR "DoubleTalk PC - cannot register device\n"); return 0; } if (dtlk_dev_probe() == 0) printk(", MAJOR %d\n", dtlk_major); init_timer(&dtlk_timer); dtlk_timer.function = dtlk_timer_tick; dtlk_process_list = NULL; return 0;}#ifdef MODULEint init_module(void){ return dtlk_init();}void cleanup_module(void){ dtlk_write_bytes("goodbye", 8); current->state = TASK_INTERRUPTIBLE; schedule_timeout(5 * HZ / 10); /* nap 0.50 sec but could be awakened earlier by signals... */ dtlk_write_tts(DTLK_CLEAR); unregister_chrdev(dtlk_major, "dtlk"); release_region(dtlk_port_lpc, DTLK_IO_EXTENT);}#endif/* ------------------------------------------------------------------------ *//* sleep for ms milliseconds */static void dtlk_delay(int ms){ current->state = TASK_INTERRUPTIBLE; schedule_timeout((ms * HZ + 1000 - HZ) / 1000); current->state = TASK_RUNNING;}static int dtlk_readable(void){ TRACE_TEXT(" dtlk_readable"); return inb_p(dtlk_port_lpc) != 0x7f;}static int dtlk_writeable(void){ /* TRACE_TEXT(" dtlk_writeable"); */#ifdef TRACING printk(" dtlk_writeable(%02x)", inb_p(dtlk_port_tts));#endif return inb_p(dtlk_port_tts) & TTS_WRITABLE;}static int __init dtlk_dev_probe(void){ unsigned int testval = 0; int i = 0; struct dtlk_settings *sp; if (dtlk_port_lpc | dtlk_port_tts) return -EBUSY; for (i = 0; dtlk_portlist[i]; i++) {#if 0 printk("DoubleTalk PC - Port %03x = %04x\n", dtlk_portlist[i], (testval = inw_p(dtlk_portlist[i])));#endif if (check_region(dtlk_portlist[i], DTLK_IO_EXTENT)) continue; testval = inw_p(dtlk_portlist[i]); if ((testval &= 0xfbff) == 0x107f) { request_region(dtlk_portlist[i], DTLK_IO_EXTENT, "dtlk"); dtlk_port_lpc = dtlk_portlist[i]; dtlk_port_tts = dtlk_port_lpc + 1; sp = dtlk_interrogate(); printk("DoubleTalk PC at %03x-%03x, " "ROM version %s, serial number %u", dtlk_portlist[i], dtlk_portlist[i] + DTLK_IO_EXTENT - 1, sp->rom_version, sp->serial_number); /* put LPC port into known state, so dtlk_readable() gives valid result */ outb_p(0xff, dtlk_port_lpc); /* INIT string and index marker */ dtlk_write_bytes("\036\1@\0\0012I\r", 8); /* posting an index takes 18 msec. Here, we wait up to 100 msec to see whether it appears. */ dtlk_delay(100); dtlk_has_indexing = dtlk_readable();#ifdef INSCOPE {/* This macro records ten samples read from the LPC port, for later display */#define LOOK \for (i = 0; i < 10; i++) \ { \ buffer[b++] = inb_p(dtlk_port_lpc); \ __delay(loops_per_sec/1000000); \ } char buffer[1000]; int b = 0, i, j; LOOK outb_p(0xff, dtlk_port_lpc); buffer[b++] = 0; LOOK dtlk_write_bytes("\0012I\r", 4); buffer[b++] = 0; __delay(50 * loops_per_sec / 1000); outb_p(0xff, dtlk_port_lpc); buffer[b++] = 0; LOOK printk("\n"); for (j = 0; j < b; j++) printk(" %02x", buffer[j]); printk("\n"); }#endif /* INSCOPE */#ifdef OUTSCOPE {/* This macro records ten samples read from the TTS port, for later display */#define LOOK \for (i = 0; i < 10; i++) \ { \ buffer[b++] = inb_p(dtlk_port_tts); \ __delay(loops_per_sec/1000000); /* 1 us */ \ } char buffer[1000]; int b = 0, i, j; __delay(loops_per_sec / 100); /* 10 ms */ LOOK outb_p(0x03, dtlk_port_tts); buffer[b++] = 0; LOOK LOOK printk("\n"); for (j = 0; j < b; j++) printk(" %02x", buffer[j]); printk("\n"); }#endif /* OUTSCOPE */ dtlk_write_bytes("Double Talk found", 18); return 0; } } printk(KERN_INFO "\nDoubleTalk PC - not found\n"); return -ENODEV;}/* static void dtlk_handle_error(char op, char rc, unsigned int minor) { printk(KERN_INFO"\nDoubleTalk PC - MINOR: %d, OPCODE: %d, ERROR: %d\n", minor, op, rc); return; } *//* interrogate the DoubleTalk PC and return its settings */static struct dtlk_settings *dtlk_interrogate(void){ unsigned char *t; static char buf[sizeof(struct dtlk_settings) + 1]; int total, i; static struct dtlk_settings status; TRACE_TEXT("(dtlk_interrogate"); dtlk_write_bytes("\030\001?", 3); for (total = 0, i = 0; i < 50; i++) { buf[total] = dtlk_read_tts(); if (total > 2 && buf[total] == 0x7f) break; if (total < sizeof(struct dtlk_settings)) total++; } /* if (i==50) printk("interrogate() read overrun\n"); for (i=0; i<sizeof(buf); i++) printk(" %02x", buf[i]); printk("\n"); */ t = buf; status.serial_number = t[0] + t[1] * 256; /* serial number is little endian */ t += 2; i = 0; while (*t != '\r') { status.rom_version[i] = *t; if (i < sizeof(status.rom_version) - 1) i++; t++; } status.rom_version[i] = 0; t++; status.mode = *t++; status.punc_level = *t++; status.formant_freq = *t++; status.pitch = *t++; status.speed = *t++; status.volume = *t++; status.tone = *t++; status.expression = *t++; status.ext_dict_loaded = *t++; status.ext_dict_status = *t++; status.free_ram = *t++; status.articulation = *t++; status.reverb = *t++; status.eob = *t++; status.has_indexing = dtlk_has_indexing; TRACE_RET; return &status;}static char dtlk_read_tts(void){ int portval, retries = 0; char ch; TRACE_TEXT("(dtlk_read_tts"); /* verify DT is ready, read char, wait for ACK */ do { portval = inb_p(dtlk_port_tts); } while ((portval & TTS_READABLE) == 0 && retries++ < DTLK_MAX_RETRIES); if (retries == DTLK_MAX_RETRIES) printk(KERN_ERR "dtlk_read_tts() timeout\n"); ch = inb_p(dtlk_port_tts); /* input from TTS port */ ch &= 0x7f; outb_p(ch, dtlk_port_tts); retries = 0; do { portval = inb_p(dtlk_port_tts); } while ((portval & TTS_READABLE) != 0 && retries++ < DTLK_MAX_RETRIES); if (retries == DTLK_MAX_RETRIES) printk(KERN_ERR "dtlk_read_tts() timeout\n"); TRACE_RET; return ch;}static char dtlk_read_lpc(void){ int retries = 0; char ch; TRACE_TEXT("(dtlk_read_lpc"); /* no need to test -- this is only called when the port is readable */ ch = inb_p(dtlk_port_lpc); /* input from LPC port */ outb_p(0xff, dtlk_port_lpc); /* acknowledging a read takes 3-4 usec. Here, we wait up to 20 usec for the acknowledgement */ retries = (loops_per_sec * 20) / 1000000; while (inb_p(dtlk_port_lpc) != 0x7f && --retries > 0); if (retries == 0) printk(KERN_ERR "dtlk_read_lpc() timeout\n"); TRACE_RET; return ch;}#ifdef NEVERstatic char dtlk_write_byte(unsigned int minor, const char *buf){ char ch; int err; /* TRACE_TEXT("(dtlk_write_byte"); */ err = get_user(ch, buf); /* printk(" dtlk_write_byte(%d, 0x%02x)", minor, (int)ch); */ ch = dtlk_write_tts(ch); /* TRACE_RET; */ return ch;}#endif /* NEVER *//* write n bytes to tts port */static char dtlk_write_bytes(const char *buf, int n){ char val = 0; /* printk("dtlk_write_bytes(\"%-*s\", %d)\n", n, buf, n); */ TRACE_TEXT("(dtlk_write_bytes"); while (n-- > 0) val = dtlk_write_tts(*buf++); TRACE_RET; return val;}static char dtlk_write_tts(char ch){ int retries = 0;#ifdef TRACING printk(" dtlk_write_tts("); if (' ' <= ch && ch <= '~') printk("'%c'", ch); else printk("0x%02x", ch);#endif if (ch != DTLK_CLEAR) /* no flow control for CLEAR command */ while ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0 && retries++ < DTLK_MAX_RETRIES) /* DT ready? */ ; if (retries == DTLK_MAX_RETRIES) printk(KERN_ERR "dtlk_write_tts() timeout\n"); outb_p(ch, dtlk_port_tts); /* output to TTS port */ /* the RDY bit goes zero 2-3 usec after writing, and goes 1 again 180-190 usec later. Here, we wait up to 10 usec for the RDY bit to go zero. */ for (retries = 0; retries < loops_per_sec / 100000; retries++) if ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0) break;#ifdef TRACING printk(")\n");#endif return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -