📄 clmodem.c
字号:
/* * CLModem v0.3.0 - CLM Linux Kernel Module * * Copyright (C) 2000 Mikhail Moreyra * * This file may be redistributed under the terms of the GNU Public * License. */#include <linux/kernel.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/sched.h>#include <linux/ioport.h>#include <linux/wrapper.h>#include <asm/uaccess.h>#include <linux/tqueue.h>#include <linux/interrupt.h>#include <linux/string.h>#include <linux/ctype.h>#include "clm_config.h"#include "clm_dspdrv.h"#include "clm_modem.h"#include "clmodem.h"#define MODEM_VENDOR_ID PCI_VENDOR_ID_CIRRUS#define CL_MD5620DT_ID 0x4000MODULE_AUTHOR("Mikhail Moreyra");int BaseIOAddress = CLM_BASE_IO_ADDRESS;int modem_irq = CLM_IRQ;extern volatile int modem_has_connected;#define WAKEUP_CHARS 256static struct tty_driver clm_driver;static int clm_refcount;static struct tty_struct *clm_table[1];static struct termios *clm_termios[1];static struct termios *clm_termios_locked[1];struct tty_struct *clm_tty = NULL;static int clm_opened = 0;static int modem_initialized = 0;volatile int need_write_unblock = 0;char command[64], cmd_resp[64];int cmdp = 0;int resp = 0;void receive_chars(void *);intsetup_clm(void){ struct pci_dev *dev = NULL; dev = pci_find_device(MODEM_VENDOR_ID, CL_MD5620DT_ID, dev); if (dev) { Msg("CL-MD5620DT modem found.\n");#if 0 Dbg("Vendor ID: %x\n", dev->vendor); Dbg("Device ID: %x\n", dev->device); Dbg("IRQ : %d\n", dev->irq); Dbg("I/O : %#lx\n", dev->base_address[0]); Dbg("I/O : %#lx\n", dev->base_address[1] - 1); /* ??? */#endif if (modem_irq != dev->irq) { Msg("The configured IRQ is wrong. Should be %d\n", dev->irq); return -1; } if (BaseIOAddress != dev->base_address[1]-1) { /* ? */ Msg("The configured BaseIOAddress is wrong. Should be %#lx\n", dev->base_address[1] - 1); return -1; } return 1; } else { Msg("Couldn't find a CL-MD5620DT modem\n"); return -1; }}static voidwrite_unblock(void *x){ struct tty_struct *tty = clm_tty; Dbg("CLM: Unblocking Writing...\n"); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait);}static voidirq_handler(int irq, void *dev_id, struct pt_regs *regs ){ static struct tq_struct rxtask = {NULL, 0, receive_chars, NULL}; static struct tq_struct txtask = {NULL, 0, write_unblock, NULL}; /* Modem IRQ Handler */ dspdrv_CommRamISR(); /* Sched BH */ if (modem_has_connected && rx_count()) { queue_task(&rxtask, &tq_immediate); mark_bh(IMMEDIATE_BH); } if (need_write_unblock && (tx_count() < WAKEUP_CHARS)) { need_write_unblock = 0; queue_task(&txtask, &tq_immediate); mark_bh(IMMEDIATE_BH); }}/***************************************************/static intclm_open(struct tty_struct *tty, struct file *filp){ int dev; MOD_INC_USE_COUNT; dev = MINOR(tty->device); if (dev != 0) { MOD_DEC_USE_COUNT; return -ENODEV; } Dbg("CLM: clm_open : (%d)\n", clm_opened); if (clm_opened > 10) return -EBUSY; clm_opened++; if (!clm_tty) clm_tty = tty; else if (clm_tty != tty) Msg("CLM ERROR: clm_tty doesn't match!\n"); tty->low_latency = 1; /* low latency ? */ return 0;}static voidclm_close(struct tty_struct *tty, struct file *filp){ Dbg("CLM: clm_close : (%d)\n", clm_opened-1); clm_opened--; if(clm_opened == 0) { if (modem_initialized) { modem_initialized = 0; line_io_enable(0); set_hook_relay(0); if (modem_has_connected) { end_connection(); print_io_stats(1); } reset_modem(); } clm_tty = NULL; } MOD_DEC_USE_COUNT;}intcmdr_char(void){ static int i = 0; if (resp) { resp--; return cmd_resp[i++]; } else { i = 0; return -1; }}voidreceive_chars(void *x){ struct tty_struct *tty = clm_tty; int ch; while (1) { if (tty->flip.count >= TTY_FLIPBUF_SIZE) { Dbg("CLM: TTY_FLIPBUF_SIZE Full\n"); break; } if (modem_has_connected) { if ((ch = read_char()) == -1) break; } else { if ((ch = cmdr_char()) == -1) break; } *tty->flip.char_buf_ptr = ch; *tty->flip.flag_buf_ptr = 0; tty->flip.char_buf_ptr++; tty->flip.flag_buf_ptr++; tty->flip.count++; } if (tty->flip.count) { /* Dbg("CLM: --> RX flip count: %d (rxq: %d - txq: %d)\n", */ /* tty->flip.count, rx_count(), tx_count()); */ } tty_flip_buffer_push(tty);}voidset_resp(char *msg){ int i = 0; while(*msg) { if (i >= 64) break; cmd_resp[i++] = *msg; msg++; } resp = i;}voidexec_cmd(void){ int cstat = 0; if (cmdp < 1) return; /* Dbg("Executing command\n"); */ if(cmdp >= 63) { set_resp("\r\nERROR: Command too long\r\n"); } else if(strcmp(command, "INFO") == 0) { set_resp("CLModem v0.3.0 - Copyright (C) 2000 Mikhail Moreyra\r\n"); } else if(strcmp(command, "INIT") == 0) { if (!modem_initialized) { init_modem(); modem_initialized = 1; } set_volume(VOL_MEDIUM); set_resp("OK\r\n"); } else if(strcmp(command, "RESET") == 0) { if (modem_initialized) { reset_modem(); modem_initialized = 0; } set_resp("OK\r\n"); } else if(!modem_initialized) { set_resp("ERROR: Modem not Initialized\r\n"); } else if(strcmp(command, "SPKR ON") == 0) { set_speaker(SPKR_ON); set_resp("OK\r\n"); } else if(strcmp(command, "SPKR OFF") == 0) { set_speaker(SPKR_OFF); set_resp("OK\r\n"); } else if(strncmp(command, "SPKRVOL ", 8) == 0) { int vol = 0; switch (command[8]) { case '0': vol = 0; break; case '1': vol = 1; break; case '2': vol = 2; break; case '3': vol = 3; break; default: vol = 0; } set_volume(vol); set_resp("OK\r\n"); } else if(strncmp(command, "DIAL ", 5) == 0) { char *phone; set_hook_relay(1); wait_for_dialtone(); phone = (char *) &command[5]; dial_number(TONE_DIALING, phone); if (orig_modem_connection()) { set_resp("CONNECT\r\n"); } else set_resp("ERROR: Couldn't connect\r\n"); cstat = modem_has_connected; } else set_resp("ERROR: Unknown Command\r\n"); modem_has_connected = 0; receive_chars(0); modem_has_connected = cstat; cmdp = 0;}static intclm_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count){ unsigned char c; int i = 0; if (!tty) return 0; /* Dbg("CLM: clm_write (fu: %d, cnt: %d, txq: %d, rxq: %d)\n", */ /* from_user, count, tx_count(), rx_count()); */ while (count) { if (from_user) { get_user(c, buf++); } else { c = *(buf++); } if (modem_has_connected) { if (write_char(c) == -1) break; else i++; count--; } else { /* Command Mode */ if (((c == '\r') || (c == '\n')) || (cmdp >= 63)) { command[cmdp] = '\0'; exec_cmd(); return count; } command[cmdp++] = toupper(c); count--; i++; } } if (count) { Dbg("CLM: Write Error (%d left) will block now\n", count); need_write_unblock = 1; } return i;}static voidclm_put_char(struct tty_struct *tty, unsigned char ch){ Dbg("CLM: clm_put_char\n"); if (write_char(ch) == -1) Dbg("CLM: Couldn't put char\n");}static voidclm_flush_chars(struct tty_struct *tty){ Dbg("CLM: clm_flush_chars\n");}static intclm_write_room(struct tty_struct *tty){ Dbg("CLM: clm_write_room\n"); if (modem_has_connected) return tx_room(); else return 63;}static intclm_chars_in_buffer(struct tty_struct *tty){ /* Dbg("CLM: clm_chars_in_buffer\n"); */ return tx_count();}static voidclm_flush_buffer(struct tty_struct *tty){ Dbg("CLM: clm_flush_buffer\n"); wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty);}static intclm_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){ switch(cmd) { case IOCTL_INIT: if (!modem_initialized) { init_modem(); modem_initialized = 1; } break; case IOCTL_STAT: Dbg("CLM_STAT: rxc= %d - txc= %d\n", get_rx_count(), get_tx_count()); break; case IOCTL_DELAY: delay(arg); break; case IOCTL_SET_HOOK: Dbg("Setting Hook: %ld\n", arg); set_hook_relay(arg); break; case IOCTL_SET_SPKR: if (!modem_initialized) return 1; Dbg("Setting Speaker: %ld\n", arg); set_speaker(arg); break; case IOCTL_SET_SPKR_VOL: if (!modem_initialized) return 1; Dbg("Setting Speaker Vol: %ld\n", arg); set_volume(arg); break; case IOCTL_WAIT_DIALTONE: if (!modem_initialized) return 1; return wait_for_dialtone(); break; case IOCTL_DIAL_NUMBER: if (!modem_initialized) return 1; dial_number(TONE_DIALING, (char *) arg); break; case IOCTL_WAIT_ANSWER: if (!modem_initialized) return 1; return wait_for_answer(); break; case IOCTL_WAIT_CARRIER: if (!modem_initialized) return 1; return wait_for_carrier(); break; case IOCTL_ORIG_CONN: if (!modem_initialized) return 1; return orig_modem_connection(); break; default: /* Dbg("CLM: Unknown device ioctl %x\n", cmd); */ return -ENOIOCTLCMD; break; } return 0;}static voidclm_throttle(struct tty_struct * tty){ Dbg("CLM: clm_throttle not implemented\n");}static voidclm_unthrottle(struct tty_struct * tty){ Dbg("CLM: clm_unthrottle not implemented\n");}static voidclm_send_xchar(struct tty_struct *tty, char ch){ Dbg("CLM: clm_send_xchar\n");}static voidclm_set_termios(struct tty_struct *tty, struct termios *old_termios){ Dbg("CLM: clm_set_termios not implemented\n");}static voidclm_stop(struct tty_struct *tty){ Dbg("CLM: clm_stop\n");}static voidclm_start(struct tty_struct *tty){ Dbg("CLM: clm_start\n");}static voidclm_hangup(struct tty_struct *tty){ Dbg("CLM: clm_hangup\n"); if (modem_initialized) { modem_initialized = 0; line_io_enable(0); set_hook_relay(0); if (modem_has_connected) { end_connection(); print_io_stats(1); } reset_modem(); }}static voidclm_break(struct tty_struct *tty, int break_state){ Dbg("CLM: clm_break\n");}static voidclm_wait_until_sent(struct tty_struct *tty, int timeout){ Dbg("CLM: clm_wait_until_sent\n"); while(tx_count()) { delay(10); }}/**************************************************/intinit_module(void){ Msg("CLModem v0.3.0\n"); Msg(" Copyright (C) 2000 Mikhail Moreyra\n"); Msg(" USE IT AT YOUR OWN RISK!\n"); if (check_region(BaseIOAddress, 256)) { Msg("CLM ERROR: I/O Ports already in use.\n"); return -1; } #ifdef DETECT_PCI_MODEM if (setup_clm() == -1) return -1;#endif if (request_irq(modem_irq, irq_handler, 0, "CLModem", NULL)) { Msg("ERROR: Couldn't get IRQ\n"); return -1; } request_region(BaseIOAddress, 256, "CLModem"); memset(&clm_driver, 0, sizeof(struct tty_driver)); clm_driver.magic = TTY_DRIVER_MAGIC; clm_driver.driver_name = "clmodem"; clm_driver.name = CLM_DEVICE_NAME; clm_driver.major = CLM_MAJOR_NUM; clm_driver.minor_start = 0; clm_driver.num = 1; /* Just one */ clm_driver.type = TTY_DRIVER_TYPE_SERIAL; clm_driver.subtype = SERIAL_TYPE_NORMAL; clm_driver.init_termios = tty_std_termios; clm_driver.init_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; clm_driver.flags = TTY_DRIVER_REAL_RAW; clm_driver.refcount = &clm_refcount; clm_driver.table = clm_table; clm_driver.termios = clm_termios; clm_driver.termios_locked = clm_termios_locked; clm_driver.open = clm_open; clm_driver.close = clm_close; clm_driver.write = clm_write; clm_driver.put_char = clm_put_char; clm_driver.flush_chars = clm_flush_chars; clm_driver.write_room = clm_write_room; clm_driver.chars_in_buffer = clm_chars_in_buffer; clm_driver.flush_buffer = clm_flush_buffer; clm_driver.ioctl = clm_ioctl; clm_driver.throttle = clm_throttle; clm_driver.unthrottle = clm_unthrottle; clm_driver.send_xchar = clm_send_xchar; clm_driver.set_termios = clm_set_termios; clm_driver.stop = clm_stop; clm_driver.start = clm_start; clm_driver.hangup = clm_hangup; clm_driver.break_ctl = clm_break; clm_driver.wait_until_sent = clm_wait_until_sent; if (tty_register_driver(&clm_driver)) { Msg("Couldn't register CLM tty driver\n"); return -1; } return 0;}voidcleanup_module(void){ int rv; if ((rv = tty_unregister_driver(&clm_driver))) Msg("CLModem: failed to unregister CLM driver (%d)\n", rv); else Msg("CLModem un-installed\n"); release_region(BaseIOAddress, 256); free_irq(modem_irq, NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -