/*************************************** * CWKEYER 0.1 * * * * Author : Ivo Simicevic, 9A3TY * * ivo@ultra.hr * * * * This code is under GPL * * Modified by PA0RCT for TLF-0.2 * ****************************************/ /* Communication: CWTONE = 0 : Mute CWTONE = 1 : Stop message CWTONE < 200 : Weight in ms. CWTONE >= 200 : Sidetone in Hz */ #include #include #include #include #include #include #include #include #include #include #include #include "cwkeyioctl.h" #define RBR(iobase) (iobase+0) #define THR(iobase) (iobase+0) #define IER(iobase) (iobase+1) #define IIR(iobase) (iobase+2) #define FCR(iobase) (iobase+2) #define LCR(iobase) (iobase+3) #define MCR(iobase) (iobase+4) #define LSR(iobase) (iobase+5) #define MSR(iobase) (iobase+6) #define SCR(iobase) (iobase+7) #define DLL(iobase) (iobase+0) #define DLM(iobase) (iobase+1) #define SER_EXTENT 8 #define BUF_SIZE 500 MODULE_PARM(iobase,"i"); MODULE_PARM(irq,"i"); static int major=230; static int dot_ticks=5; // Default keyer speed is 60 lpm static int dash_ticks=15; static unsigned int count=1491; // Counter value for 800 Hz static unsigned int remainder=0; static unsigned int msweight=0; static unsigned int stopflag=0; static int iobase = 0x3f8; static int irq = 4; static int inDotDash; static int mute=0; void key_out_off () { outb (0x02,MCR(iobase)); if (!mute) outb(inb_p(0x61)&0xFC, 0x61); return; } void key_out_on (unsigned int ticks) { /* changes in structure in timer.h for kernel 2.4.x - VE3RZ */ static struct timer_list sound_timer = { { NULL,NULL}, 0, 0, key_out_off, NULL}; outb (0x03,MCR(iobase)); /* DTR line */ del_timer(&sound_timer); if (!mute) { outb_p(inb_p(0x61)|3, 0x61); outb_p(0xB6, 0x43); outb_p(count & 0xff, 0x42); outb((count >> 8) & 0xff, 0x42); } if (ticks == dot_ticks) udelay (remainder + (1000 * msweight)); else udelay (3 * remainder + (1000 * msweight)); if (ticks) { sound_timer.expires = jiffies+ticks; add_timer(&sound_timer); } return; } int cwkeyer_open (struct inode *cwinode,struct file *cwfile) { MOD_INC_USE_COUNT; return 0; } int cwkeyer_release (struct inode *cwinode,struct file *cwfile) { key_out_off (); MOD_DEC_USE_COUNT; return 0; } void dot_pause () { current->state = TASK_INTERRUPTIBLE; schedule_timeout (dot_ticks+dot_ticks); udelay(remainder); return; } void dash_pause () { current->state = TASK_INTERRUPTIBLE; schedule_timeout (dash_ticks+dot_ticks); udelay (remainder); return; } short morse_code [128] = { 0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00, // ..... ..... 0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00, // ..... ..... 0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00, // ..... ..... 0x00,0x00,0x00,0x10,0x48, 0x00,0x13,0x00,0x40,0x78, // .. !" #$%&' 0xB0,0xB4,0x00,0x50,0xCC, 0x84,0x54,0x90,0xF8,0x78, // ()*+, -./01 0x38,0x18,0x08,0x00,0x80, 0xC0,0xE0,0xF0,0xE0,0xA8, // 23456 789:; 0x14,0x88,0x8A,0x30,0x00, 0x40,0x80,0xA0,0x80,0x00, // <=>?@ ABCDE 0x20,0xC0,0x00,0x00,0x70, 0xA0,0x40,0xC0,0x80,0xE0, // FGHIJ KLMNO 0x60,0xD0,0x40,0x00,0x80, 0x20,0x10,0x60,0x90,0xB0, // PQRST UVWXY 0xC0,0x00,0x00,0x00,0x00, 0x34,0x00,0x40,0x80,0xA0, // Z[\]^ _`abc 0x80,0x00,0x20,0xC0,0x00, 0x00,0x70,0xA0,0x40,0xC0, // defgh ijklm 0x80,0xE0,0x60,0xD0,0x40, 0x00,0x80,0x20,0x10,0x60, // nopqr stuvw 0x90,0xB0,0xC0,0x00,0x00, 0x00,0x00,0x00 // xyz{| }~ }; short morse_code_len [128] = { 0,0,0,0,0, 0,0,0,0,0, // ..... ..... 0,0,0,0,0, 0,0,0,0,0, // ..... ..... 0,0,0,0,0, 0,0,0,0,0, // ..... ..... 0,0,0,5,6, 0,7,0,5,6, // .. !" #$%&' 5,6,0,5,6, 6,6,5,5,5, // ()*+, -./01 5,5,5,5,5, 5,5,5,6,6, // 23456 789:; 6,5,7,6,0, 2,4,4,3,1, // <=>?@ ABCDE 4,3,4,2,4, 3,4,2,2,3, // FGHIJ KLMNO 4,4,3,3,1, 3,4,3,4,4, // PQRST UVWXY 4,0,0,0,0, 6,0,2,4,4, // Z[\]^ _`abc 3,1,4,3,4, 2,4,3,4,2, // defgh ijklm 2,3,4,4,3, 3,1,3,4,3, // nopqr stuvw 4,4,4,0,0, 0,0,0 // xyz{| }~ }; void dash () { key_out_on (dash_ticks); dash_pause (); udelay (3*remainder); } void dot () { key_out_on (dot_ticks); dot_pause (); udelay (remainder); } ssize_t cwkeyer_write (struct file *cwfile,const char *cwtext, size_t cwlen,loff_t *cwinode) { int i; char buf[BUF_SIZE]; unsigned char pos,code,len; int dotdash; if (cwlen > BUF_SIZE) cwlen = BUF_SIZE; copy_from_user (buf,cwtext,cwlen); for (i=0;i 32766)) return -EINVAL; if (hz < 200) msweight = hz; else{ mute=0; count = 1193180 / hz; } break; case CWSPEED: speed = cwarg; if ((!speed) || (speed>99)) return -EINVAL; dot_ticks = 120/speed; dash_ticks = dot_ticks * 3; fraction = 120.0/speed; fraction = fraction - dot_ticks; remainder = (int) (fraction * 10000) ; break; default : return -ENOTTY; } return 0; } /* Changes in size of structure in fs.h for kernel 2.4.x - VE3RZ */ struct file_operations cwkeyer_fops = { NULL, NULL, // lseek NULL, // read cwkeyer_write, NULL, // readdir NULL, // select cwkeyer_ioctl, // ioctl NULL, // mmap cwkeyer_open, NULL, cwkeyer_release, NULL, NULL, NULL, NULL, NULL, 0 }; void cwkeyer_interrupt (int irq, void *dev_id, struct pt_regs *regs) { unsigned char icode,dummy; icode = inb (IIR(iobase)) & 0x07; switch (icode) { case 6 : dummy = inb(LSR(iobase)); break; case 4 : dummy = inb(RBR(iobase)); break; case 2 : break; default: break; } } int cwkeyer_init () { if (check_region(iobase,SER_EXTENT)) { printk (KERN_INFO "-EACCES to 0x%x-0x%x\n",iobase,iobase+SER_EXTENT); return -EACCES; } request_region (iobase,SER_EXTENT,"cwkeyer"); outb (0,IER(iobase)); if (request_irq(irq,cwkeyer_interrupt,SA_INTERRUPT,"cwkeyer",NULL)) { printk (KERN_INFO "-EBUSY to irq %d\n",irq); return -EBUSY; } inDotDash = 0; key_out_off (); return 0; } int init_module(void) { int result; EXPORT_NO_SYMBOLS; result = register_chrdev (major,"cwkeyer",&cwkeyer_fops); if (result<0) { printk (KERN_WARNING "CWkeyer: Can't register major %d\n",major); return result; } if (cwkeyer_init ()) return 1; printk (KERN_INFO "CWkeyer up - major=%d.\n",major); return 0; } void cleanup_module(void) { free_irq (irq,NULL); release_region (iobase,SER_EXTENT); unregister_chrdev (major,"cwkeyer"); printk (KERN_INFO "CWkeyer down.\n"); }