^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Original driver code supplied by Multi-Tech
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Changes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * 1/9/98 alan@lxorguk.ukuu.org.uk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Merge to 2.0.x kernel tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Obtain and use official major/minors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Loader switched to a misc device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * (fixed range check bug as a side effect)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Printk clean up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * 9/12/98 alan@lxorguk.ukuu.org.uk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Rough port to 2.1.x
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * 10/6/99 sameer Merged the ISA and PCI drivers to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * a new unified driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * 3/9/99 sameer Added support for ISI4616 cards.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * 16/9/99 sameer We do not force RTS low anymore.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * This is to prevent the firmware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * from getting confused.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * 26/10/99 sameer Cosmetic changes:The driver now
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * dumps the Port Count information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * along with I/O address and IRQ.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * 13/12/99 sameer Fixed the problem with IRQ sharing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * 10/5/00 sameer Fixed isicom_shutdown_board()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * to not lower DTR on all the ports
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * when the last port on the card is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * closed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * 10/5/00 sameer Signal mask setup command added
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * to isicom_setup_port and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * isicom_shutdown_port.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * 24/5/00 sameer The driver is now SMP aware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * 27/11/00 Vinayak P Risbud Fixed the Driver Crash Problem
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * 03/01/01 anil .s Added support for resetting the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * internal modems on ISI cards.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * 08/02/01 anil .s Upgraded the driver for kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * 2.4.x
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * 11/04/01 Kevin Fixed firmware load problem with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * ISIHP-4X card
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * 30/04/01 anil .s Fixed the remote login through
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * ISI port problem. Now the link
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * does not go down before password
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * prompt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * 03/05/01 anil .s Fixed the problem with IRQ sharing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * among ISI-PCI cards.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * 03/05/01 anil .s Added support to display the version
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * info during insmod as well as module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * listing by lsmod.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * 10/05/01 anil .s Done the modifications to the source
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * file and Install script so that the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * same installation can be used for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * 2.2.x and 2.4.x kernel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * 06/06/01 anil .s Now we drop both dtr and rts during
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * shutdown_port as well as raise them
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * during isicom_config_port.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * 09/06/01 acme@conectiva.com.br use capable, not suser, do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * restore_flags on failure in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * isicom_send_break, verify put_user
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * result
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * 11/02/03 ranjeeth Added support for 230 Kbps and 460 Kbps
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * Baud index extended to 21
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * 20/03/03 ranjeeth Made to work for Linux Advanced server.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * Taken care of license warning.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * 10/12/03 Ravindra Made to work for Fedora Core 1 of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * Red Hat Distribution
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * 06/01/05 Alan Cox Merged the ISI and base kernel strands
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * into a single 2.6 driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * ***********************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * To use this driver you also need the support package. You
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * can find this in RPM format on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * ftp://ftp.linux.org.uk/pub/linux/alan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * You can find the original tools for this direct from Multitech
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * ftp://ftp.multitech.com/ISI-Cards/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * Having installed the cards the module options (/etc/modprobe.d/)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * options isicom io=card1,card2,card3,card4 irq=card1,card2,card3,card4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * Omit those entries for boards you don't have installed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * TODO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * Merge testing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * 64-bit verification
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #include <linux/firmware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) #include <linux/tty.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #include <linux/tty_flip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #include <linux/termios.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #include <linux/serial.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) #include <linux/timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) #include <linux/isicom.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #define InterruptTheCard(base) outw(0, (base) + 0xc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) #define ClearInterrupt(base) inw((base) + 0x0a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) #define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) #define isicom_paranoia_check(a, b, c) 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static int isicom_probe(struct pci_dev *, const struct pci_device_id *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) static void isicom_remove(struct pci_dev *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static const struct pci_device_id isicom_pci_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) { PCI_DEVICE(VENDOR_ID, 0x2028) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) { PCI_DEVICE(VENDOR_ID, 0x2051) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) { PCI_DEVICE(VENDOR_ID, 0x2052) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) { PCI_DEVICE(VENDOR_ID, 0x2053) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) { PCI_DEVICE(VENDOR_ID, 0x2054) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) { PCI_DEVICE(VENDOR_ID, 0x2055) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) { PCI_DEVICE(VENDOR_ID, 0x2056) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) { PCI_DEVICE(VENDOR_ID, 0x2057) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) { PCI_DEVICE(VENDOR_ID, 0x2058) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) { 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) MODULE_DEVICE_TABLE(pci, isicom_pci_tbl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) static struct pci_driver isicom_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .name = "isicom",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) .id_table = isicom_pci_tbl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) .probe = isicom_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .remove = isicom_remove
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) static int prev_card = 3; /* start servicing isi_card[0] */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static struct tty_driver *isicom_normal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static void isicom_tx(struct timer_list *unused);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static void isicom_start(struct tty_struct *tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) static DEFINE_TIMER(tx, isicom_tx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /* baud index mappings from linux defns to isi */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) static signed char linuxb_to_isib[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct isi_board {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) unsigned long base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) unsigned char port_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) unsigned short status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) unsigned short port_status; /* each bit for each port */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) unsigned short shift_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) struct isi_port *ports;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) signed char count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) unsigned int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) struct isi_port {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) unsigned short magic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) struct tty_port port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) u16 channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) u16 status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct isi_board *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) unsigned char *xmit_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) int xmit_head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) int xmit_tail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) int xmit_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) static struct isi_board isi_card[BOARD_COUNT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) static struct isi_port isi_ports[PORT_COUNT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * Locking functions for card level locking. We need to own both
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * the kernel lock for the card and have the card in a position that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * it wants to talk.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) static int WaitTillCardIsFree(unsigned long base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) unsigned int count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) while (!(inw(base + 0xe) & 0x1) && count++ < 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) mdelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return !(inw(base + 0xe) & 0x1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) static int lock_card(struct isi_board *card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) unsigned long base = card->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) unsigned int retries, a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) for (retries = 0; retries < 10; retries++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) spin_lock_irqsave(&card->card_lock, card->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) for (a = 0; a < 10; a++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (inw(base + 0xe) & 0x1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) udelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) spin_unlock_irqrestore(&card->card_lock, card->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) msleep(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) pr_warn("Failed to lock Card (0x%lx)\n", card->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return 0; /* Failed to acquire the card! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) static void unlock_card(struct isi_board *card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) spin_unlock_irqrestore(&card->card_lock, card->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * ISI Card specific ops ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /* card->lock HAS to be held */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) static void raise_dtr(struct isi_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) struct isi_board *card = port->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) unsigned long base = card->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) u16 channel = port->channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (WaitTillCardIsFree(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) outw(0x8000 | (channel << card->shift_count) | 0x02, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) outw(0x0504, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) port->status |= ISI_DTR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) /* card->lock HAS to be held */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static void drop_dtr(struct isi_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) struct isi_board *card = port->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) unsigned long base = card->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) u16 channel = port->channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (WaitTillCardIsFree(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) outw(0x8000 | (channel << card->shift_count) | 0x02, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) outw(0x0404, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) port->status &= ~ISI_DTR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) /* card->lock HAS to be held */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) static inline void raise_rts(struct isi_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) struct isi_board *card = port->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) unsigned long base = card->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) u16 channel = port->channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (WaitTillCardIsFree(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) outw(0x8000 | (channel << card->shift_count) | 0x02, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) outw(0x0a04, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) port->status |= ISI_RTS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /* card->lock HAS to be held */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) static inline void drop_rts(struct isi_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) struct isi_board *card = port->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) unsigned long base = card->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) u16 channel = port->channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (WaitTillCardIsFree(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) outw(0x8000 | (channel << card->shift_count) | 0x02, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) outw(0x0804, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) port->status &= ~ISI_RTS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) /* card->lock MUST NOT be held */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) static void isicom_dtr_rts(struct tty_port *port, int on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) struct isi_port *ip = container_of(port, struct isi_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) struct isi_board *card = ip->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) unsigned long base = card->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) u16 channel = ip->channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (!lock_card(card))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) if (on) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) outw(0x8000 | (channel << card->shift_count) | 0x02, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) outw(0x0f04, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) ip->status |= (ISI_DTR | ISI_RTS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) outw(0x8000 | (channel << card->shift_count) | 0x02, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) outw(0x0C04, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) ip->status &= ~(ISI_DTR | ISI_RTS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) unlock_card(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) /* card->lock HAS to be held */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) static void drop_dtr_rts(struct isi_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) struct isi_board *card = port->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) unsigned long base = card->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) u16 channel = port->channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (WaitTillCardIsFree(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) outw(0x8000 | (channel << card->shift_count) | 0x02, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) outw(0x0c04, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) port->status &= ~(ISI_RTS | ISI_DTR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) * ISICOM Driver specific routines ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) static inline int __isicom_paranoia_check(struct isi_port const *port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) char *name, const char *routine)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) if (!port) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) pr_warn("Warning: bad isicom magic for dev %s in %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) name, routine);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (port->magic != ISICOM_MAGIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) pr_warn("Warning: NULL isicom port for dev %s in %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) name, routine);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * Transmitter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) * We shovel data into the card buffers on a regular basis. The card
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) * will do the rest of the work for us.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) static void isicom_tx(struct timer_list *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) unsigned long flags, base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) unsigned int retries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) short count = (BOARD_COUNT-1), card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) short txcount, wrd, residue, word_count, cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) struct isi_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) struct tty_struct *tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) /* find next active board */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) card = (prev_card + 1) & 0x0003;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) while (count-- > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (isi_card[card].status & BOARD_ACTIVE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) card = (card + 1) & 0x0003;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) if (!(isi_card[card].status & BOARD_ACTIVE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) goto sched_again;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) prev_card = card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) count = isi_card[card].port_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) port = isi_card[card].ports;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) base = isi_card[card].base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) spin_lock_irqsave(&isi_card[card].card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) for (retries = 0; retries < 100; retries++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if (inw(base + 0xe) & 0x1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) udelay(2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (retries >= 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) tty = tty_port_tty_get(&port->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (tty == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) goto put_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) for (; count > 0; count--, port++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) /* port not active or tx disabled to force flow control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (!tty_port_initialized(&port->port) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) !(port->status & ISI_TXOK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) txcount = min_t(short, TX_SIZE, port->xmit_cnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (txcount <= 0 || tty->stopped || tty->hw_stopped)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) if (!(inw(base + 0x02) & (1 << port->channel)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) pr_debug("txing %d bytes, port%d.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) txcount, port->channel + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) outw((port->channel << isi_card[card].shift_count) | txcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) residue = NO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) wrd = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) - port->xmit_tail));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) if (residue == YES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) residue = NO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) if (cnt > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) wrd |= (port->port.xmit_buf[port->xmit_tail]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) << 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) port->xmit_tail = (port->xmit_tail + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) & (SERIAL_XMIT_SIZE - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) port->xmit_cnt--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) txcount--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) cnt--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) outw(wrd, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) outw(wrd, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) if (cnt <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) word_count = cnt >> 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) outsw(base, port->port.xmit_buf+port->xmit_tail, word_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) port->xmit_tail = (port->xmit_tail
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) + (word_count << 1)) & (SERIAL_XMIT_SIZE - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) txcount -= (word_count << 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) port->xmit_cnt -= (word_count << 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) if (cnt & 0x0001) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) residue = YES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) wrd = port->port.xmit_buf[port->xmit_tail];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) port->xmit_tail = (port->xmit_tail + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) & (SERIAL_XMIT_SIZE - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) port->xmit_cnt--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) txcount--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) if (port->xmit_cnt <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) port->status &= ~ISI_TXOK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) if (port->xmit_cnt <= WAKEUP_CHARS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) tty_wakeup(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) put_unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) tty_kref_put(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) /* schedule another tx for hopefully in about 10ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) sched_again:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) mod_timer(&tx, jiffies + msecs_to_jiffies(10));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) * Main interrupt handler routine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) static irqreturn_t isicom_interrupt(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) struct isi_board *card = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) struct isi_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) struct tty_struct *tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) unsigned long base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) u16 header, word_count, count, channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) short byte_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) unsigned char *rp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) if (!card || !(card->status & FIRMWARE_LOADED))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) base = card->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) /* did the card interrupt us? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) if (!(inw(base + 0x0e) & 0x02))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) spin_lock(&card->card_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) * disable any interrupts from the PCI card and lower the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) * interrupt line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) outw(0x8000, base+0x04);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) ClearInterrupt(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) inw(base); /* get the dummy word out */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) header = inw(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) channel = (header & 0x7800) >> card->shift_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) byte_count = header & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (channel + 1 > card->port_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) pr_warn("%s(0x%lx): %d(channel) > port_count\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) __func__, base, channel + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) outw(0x0000, base+0x04); /* enable interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) spin_unlock(&card->card_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) port = card->ports + channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) if (!tty_port_initialized(&port->port)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) outw(0x0000, base+0x04); /* enable interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) spin_unlock(&card->card_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) tty = tty_port_tty_get(&port->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) if (tty == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) while (byte_count > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) inw(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) byte_count -= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) if (byte_count & 0x01)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) inw(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) outw(0x0000, base+0x04); /* enable interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) spin_unlock(&card->card_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) if (header & 0x8000) { /* Status Packet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) header = inw(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) switch (header & 0xff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) case 0: /* Change in EIA signals */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (tty_port_check_carrier(&port->port)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) if (port->status & ISI_DCD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) if (!(header & ISI_DCD)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) /* Carrier has been lost */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) pr_debug("%s: DCD->low.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) port->status &= ~ISI_DCD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) tty_hangup(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) } else if (header & ISI_DCD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) /* Carrier has been detected */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) pr_debug("%s: DCD->high.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) port->status |= ISI_DCD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) wake_up_interruptible(&port->port.open_wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) if (header & ISI_DCD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) port->status |= ISI_DCD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) port->status &= ~ISI_DCD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) if (tty_port_cts_enabled(&port->port)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if (tty->hw_stopped) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) if (header & ISI_CTS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) tty->hw_stopped = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) /* start tx ing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) port->status |= (ISI_TXOK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) | ISI_CTS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) tty_wakeup(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) } else if (!(header & ISI_CTS)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) tty->hw_stopped = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) /* stop tx ing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) port->status &= ~(ISI_TXOK | ISI_CTS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (header & ISI_CTS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) port->status |= ISI_CTS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) port->status &= ~ISI_CTS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if (header & ISI_DSR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) port->status |= ISI_DSR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) port->status &= ~ISI_DSR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) if (header & ISI_RI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) port->status |= ISI_RI;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) port->status &= ~ISI_RI;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) case 1: /* Received Break !!! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) tty_insert_flip_char(&port->port, 0, TTY_BREAK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if (port->port.flags & ASYNC_SAK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) do_SAK(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) tty_flip_buffer_push(&port->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) case 2: /* Statistics */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) pr_debug("%s: stats!!!\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) pr_debug("%s: Unknown code in status packet.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) } else { /* Data Packet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) count = tty_prepare_flip_string(&port->port, &rp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) byte_count & ~1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) pr_debug("%s: Can rx %d of %d bytes.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) __func__, count, byte_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) word_count = count >> 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) insw(base, rp, word_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) byte_count -= (word_count << 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) if (count & 0x0001) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) tty_insert_flip_char(&port->port, inw(base) & 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) TTY_NORMAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) byte_count -= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) if (byte_count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) pr_debug("%s(0x%lx:%d): Flip buffer overflow! dropping bytes...\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) __func__, base, channel + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) /* drain out unread xtra data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) while (byte_count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) inw(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) byte_count -= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) tty_flip_buffer_push(&port->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) outw(0x0000, base+0x04); /* enable interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) spin_unlock(&card->card_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) tty_kref_put(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) static void isicom_config_port(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) struct isi_board *card = port->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) unsigned long baud;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) unsigned long base = card->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) u16 channel_setup, channel = port->channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) shift_count = card->shift_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) unsigned char flow_ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) /* FIXME: Switch to new tty baud API */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) baud = C_BAUD(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) if (baud & CBAUDEX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) baud &= ~CBAUDEX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) /* if CBAUDEX bit is on and the baud is set to either 50 or 75
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) * then the card is programmed for 57.6Kbps or 115Kbps
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) * respectively.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) if (baud < 1 || baud > 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) tty->termios.c_cflag &= ~CBAUDEX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) baud += 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) if (baud == 15) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) /* the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) * by the set_serial_info ioctl ... this is done by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) * the 'setserial' utility.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) baud++; /* 57.6 Kbps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) baud += 2; /* 115 Kbps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) baud += 3; /* 230 kbps*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) baud += 4; /* 460 kbps*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) if (linuxb_to_isib[baud] == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) /* hang up */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) drop_dtr(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) raise_dtr(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (WaitTillCardIsFree(base) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) outw(0x8000 | (channel << shift_count) | 0x03, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) outw(linuxb_to_isib[baud] << 8 | 0x03, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) channel_setup = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) switch (C_CSIZE(tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) case CS5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) channel_setup |= ISICOM_CS5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) case CS6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) channel_setup |= ISICOM_CS6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) case CS7:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) channel_setup |= ISICOM_CS7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) case CS8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) channel_setup |= ISICOM_CS8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) if (C_CSTOPB(tty))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) channel_setup |= ISICOM_2SB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) if (C_PARENB(tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) channel_setup |= ISICOM_EVPAR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) if (C_PARODD(tty))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) channel_setup |= ISICOM_ODPAR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) outw(channel_setup, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) tty_port_set_check_carrier(&port->port, !C_CLOCAL(tty));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) /* flow control settings ...*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) flow_ctrl = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) tty_port_set_cts_flow(&port->port, C_CRTSCTS(tty));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) if (C_CRTSCTS(tty))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) flow_ctrl |= ISICOM_CTSRTS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) if (I_IXON(tty))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) flow_ctrl |= ISICOM_RESPOND_XONXOFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) if (I_IXOFF(tty))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) flow_ctrl |= ISICOM_INITIATE_XONXOFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) if (WaitTillCardIsFree(base) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) outw(0x8000 | (channel << shift_count) | 0x04, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) outw(flow_ctrl << 8 | 0x05, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) /* rx enabled -> enable port for rx on the card */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) if (C_CREAD(tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) card->port_status |= (1 << channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) outw(card->port_status, base + 0x02);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) /* open et all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) static inline void isicom_setup_board(struct isi_board *bp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) int channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) struct isi_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) bp->count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) if (!(bp->status & BOARD_INIT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) port = bp->ports;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) for (channel = 0; channel < bp->port_count; channel++, port++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) drop_dtr_rts(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) bp->status |= BOARD_ACTIVE | BOARD_INIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) /* Activate and thus setup board are protected from races against shutdown
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) by the tty_port mutex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) static int isicom_activate(struct tty_port *tport, struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) struct isi_port *port = container_of(tport, struct isi_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) struct isi_board *card = port->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) if (tty_port_alloc_xmit_buf(tport) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) spin_lock_irqsave(&card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) isicom_setup_board(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) /* discard any residual data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) if (WaitTillCardIsFree(card->base) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) outw(0x8000 | (port->channel << card->shift_count) | 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) card->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) InterruptTheCard(card->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) isicom_config_port(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) spin_unlock_irqrestore(&card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) static int isicom_carrier_raised(struct tty_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) struct isi_port *ip = container_of(port, struct isi_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) return (ip->status & ISI_DCD)?1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) static struct tty_port *isicom_find_port(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) struct isi_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) struct isi_board *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) unsigned int board;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) int line = tty->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) board = BOARD(line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) card = &isi_card[board];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) if (!(card->status & FIRMWARE_LOADED))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) /* open on a port greater than the port count for the card !!! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) if (line > ((board * 16) + card->port_count - 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) port = &isi_ports[line];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) if (isicom_paranoia_check(port, tty->name, "isicom_open"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) return &port->port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) static int isicom_open(struct tty_struct *tty, struct file *filp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) struct isi_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) struct tty_port *tport;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) tport = isicom_find_port(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) if (tport == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) port = container_of(tport, struct isi_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) tty->driver_data = port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) return tty_port_open(tport, tty, filp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) /* close et all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) /* card->lock HAS to be held */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) static void isicom_shutdown_port(struct isi_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) struct isi_board *card = port->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) if (--card->count < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) pr_debug("%s: bad board(0x%lx) count %d.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) __func__, card->base, card->count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) card->count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) /* last port was closed, shutdown that board too */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) if (!card->count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) card->status &= BOARD_ACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) static void isicom_flush_buffer(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) struct isi_board *card = port->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) spin_lock_irqsave(&card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) spin_unlock_irqrestore(&card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) tty_wakeup(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) static void isicom_shutdown(struct tty_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) struct isi_port *ip = container_of(port, struct isi_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) struct isi_board *card = ip->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) /* indicate to the card that no more data can be received
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) on this port */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) spin_lock_irqsave(&card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) card->port_status &= ~(1 << ip->channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) outw(card->port_status, card->base + 0x02);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) isicom_shutdown_port(ip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) spin_unlock_irqrestore(&card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) tty_port_free_xmit_buf(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) static void isicom_close(struct tty_struct *tty, struct file *filp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) struct isi_port *ip = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) struct tty_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) if (ip == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) port = &ip->port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) tty_port_close(port, tty, filp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) /* write et all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) static int isicom_write(struct tty_struct *tty, const unsigned char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) int count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) struct isi_board *card = port->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) int cnt, total = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) if (isicom_paranoia_check(port, tty->name, "isicom_write"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) spin_lock_irqsave(&card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) - 1, SERIAL_XMIT_SIZE - port->xmit_head));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) if (cnt <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) memcpy(port->port.xmit_buf + port->xmit_head, buf, cnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) port->xmit_cnt += cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) buf += cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) count -= cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) total += cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) port->status |= ISI_TXOK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) spin_unlock_irqrestore(&card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) return total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) /* put_char et all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) static int isicom_put_char(struct tty_struct *tty, unsigned char ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) struct isi_board *card = port->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) spin_lock_irqsave(&card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) spin_unlock_irqrestore(&card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) port->port.xmit_buf[port->xmit_head++] = ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) port->xmit_cnt++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) spin_unlock_irqrestore(&card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) /* flush_chars et all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) static void isicom_flush_chars(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) if (isicom_paranoia_check(port, tty->name, "isicom_flush_chars"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) !port->port.xmit_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) /* this tells the transmitter to consider this port for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) data output to the card ... that's the best we can do. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) port->status |= ISI_TXOK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) /* write_room et all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) static int isicom_write_room(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) int free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) if (isicom_paranoia_check(port, tty->name, "isicom_write_room"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) if (free < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) free = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) return free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) /* chars_in_buffer et all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) static int isicom_chars_in_buffer(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) if (isicom_paranoia_check(port, tty->name, "isicom_chars_in_buffer"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) return port->xmit_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) /* ioctl et all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) static int isicom_send_break(struct tty_struct *tty, int length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) struct isi_board *card = port->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) unsigned long base = card->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) if (length == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) if (!lock_card(card))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) outw((length & 0xff) << 8 | 0x00, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) outw((length & 0xff00u), base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) unlock_card(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) static int isicom_tiocmget(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) /* just send the port status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) u16 status = port->status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) return ((status & ISI_RTS) ? TIOCM_RTS : 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) ((status & ISI_DTR) ? TIOCM_DTR : 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) ((status & ISI_DCD) ? TIOCM_CAR : 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) ((status & ISI_DSR) ? TIOCM_DSR : 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) ((status & ISI_CTS) ? TIOCM_CTS : 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) ((status & ISI_RI ) ? TIOCM_RI : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) static int isicom_tiocmset(struct tty_struct *tty,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) unsigned int set, unsigned int clear)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) spin_lock_irqsave(&port->card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) if (set & TIOCM_RTS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) raise_rts(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) if (set & TIOCM_DTR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) raise_dtr(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) if (clear & TIOCM_RTS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) drop_rts(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) if (clear & TIOCM_DTR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) drop_dtr(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) spin_unlock_irqrestore(&port->card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) static int isicom_set_serial_info(struct tty_struct *tty,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) struct serial_struct *ss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) int reconfig_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) mutex_lock(&port->port.mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) (ss->flags & ASYNC_SPD_MASK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) if (!capable(CAP_SYS_ADMIN)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) if ((ss->close_delay != port->port.close_delay) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) (ss->closing_wait != port->port.closing_wait) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) ((ss->flags & ~ASYNC_USR_MASK) !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) (port->port.flags & ~ASYNC_USR_MASK))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) mutex_unlock(&port->port.mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) (ss->flags & ASYNC_USR_MASK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) port->port.close_delay = ss->close_delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) port->port.closing_wait = ss->closing_wait;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) (ss->flags & ASYNC_FLAGS));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) if (reconfig_port) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) spin_lock_irqsave(&port->card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) isicom_config_port(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) spin_unlock_irqrestore(&port->card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) mutex_unlock(&port->port.mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) static int isicom_get_serial_info(struct tty_struct *tty,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) struct serial_struct *ss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) mutex_lock(&port->port.mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) /* ss->type = ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) ss->line = port - isi_ports;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) ss->port = port->card->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) ss->irq = port->card->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) ss->flags = port->port.flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) /* ss->baud_base = ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) ss->close_delay = port->port.close_delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) ss->closing_wait = port->port.closing_wait;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) mutex_unlock(&port->port.mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) /* set_termios et all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) static void isicom_set_termios(struct tty_struct *tty,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) struct ktermios *old_termios)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) if (tty->termios.c_cflag == old_termios->c_cflag &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) tty->termios.c_iflag == old_termios->c_iflag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) spin_lock_irqsave(&port->card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) isicom_config_port(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) spin_unlock_irqrestore(&port->card->card_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) tty->hw_stopped = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) isicom_start(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) /* throttle et all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) static void isicom_throttle(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) struct isi_board *card = port->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) if (isicom_paranoia_check(port, tty->name, "isicom_throttle"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) /* tell the card that this port cannot handle any more data for now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) card->port_status &= ~(1 << port->channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) outw(card->port_status, card->base + 0x02);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) /* unthrottle et all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) static void isicom_unthrottle(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) struct isi_board *card = port->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) if (isicom_paranoia_check(port, tty->name, "isicom_unthrottle"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) /* tell the card that this port is ready to accept more data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) card->port_status |= (1 << port->channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) outw(card->port_status, card->base + 0x02);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) /* stop et all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) static void isicom_stop(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) if (isicom_paranoia_check(port, tty->name, "isicom_stop"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) /* this tells the transmitter not to consider this port for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) data output to the card. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) port->status &= ~ISI_TXOK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) /* start et all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) static void isicom_start(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) if (isicom_paranoia_check(port, tty->name, "isicom_start"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) /* this tells the transmitter to consider this port for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) data output to the card. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) port->status |= ISI_TXOK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) static void isicom_hangup(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) struct isi_port *port = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) tty_port_hangup(&port->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) * Driver init and deinit functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) static const struct tty_operations isicom_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) .open = isicom_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) .close = isicom_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) .write = isicom_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) .put_char = isicom_put_char,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) .flush_chars = isicom_flush_chars,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) .write_room = isicom_write_room,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) .chars_in_buffer = isicom_chars_in_buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) .set_termios = isicom_set_termios,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) .throttle = isicom_throttle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) .unthrottle = isicom_unthrottle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) .stop = isicom_stop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) .start = isicom_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) .hangup = isicom_hangup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) .flush_buffer = isicom_flush_buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) .tiocmget = isicom_tiocmget,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) .tiocmset = isicom_tiocmset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) .break_ctl = isicom_send_break,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) .get_serial = isicom_get_serial_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) .set_serial = isicom_set_serial_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) static const struct tty_port_operations isicom_port_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) .carrier_raised = isicom_carrier_raised,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) .dtr_rts = isicom_dtr_rts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) .activate = isicom_activate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) .shutdown = isicom_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) static int reset_card(struct pci_dev *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) const unsigned int card, unsigned int *signature)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) struct isi_board *board = pci_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) unsigned long base = board->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) unsigned int sig, portcount = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) dev_dbg(&pdev->dev, "ISILoad:Resetting Card%d at 0x%lx\n", card + 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) inw(base + 0x8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) msleep(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) outw(0, base + 0x8); /* Reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) msleep(1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) sig = inw(base + 0x4) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) if (sig != 0xa5 && sig != 0xbb && sig != 0xcc && sig != 0xdd &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) sig != 0xee) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) dev_warn(&pdev->dev, "ISILoad:Card%u reset failure (Possible "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) "bad I/O Port Address 0x%lx).\n", card + 1, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) dev_dbg(&pdev->dev, "Sig=0x%x\n", sig);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) retval = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) msleep(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) portcount = inw(base + 0x2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) if (!(inw(base + 0xe) & 0x1) || (portcount != 0 && portcount != 4 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) portcount != 8 && portcount != 16)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) card + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) retval = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) switch (sig) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) case 0xa5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) case 0xbb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) case 0xdd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) board->port_count = (portcount == 4) ? 4 : 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) board->shift_count = 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) case 0xcc:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) case 0xee:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) board->port_count = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) board->shift_count = 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) dev_info(&pdev->dev, "-Done\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) *signature = sig;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) end:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) static int load_firmware(struct pci_dev *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) const unsigned int index, const unsigned int signature)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) struct isi_board *board = pci_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) const struct firmware *fw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) unsigned long base = board->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) unsigned int a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) u16 word_count, status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) int retval = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) u8 *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) struct stframe {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) u16 addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) u16 count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) u8 data[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) } *frame;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) switch (signature) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) case 0xa5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) name = "isi608.bin";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) case 0xbb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) name = "isi608em.bin";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) case 0xcc:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) name = "isi616em.bin";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) case 0xdd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) name = "isi4608.bin";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) case 0xee:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) name = "isi4616.bin";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) dev_err(&pdev->dev, "Unknown signature.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) retval = request_firmware(&fw, name, &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) retval = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) for (frame = (struct stframe *)fw->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) frame < (struct stframe *)(fw->data + fw->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) frame = (struct stframe *)((u8 *)(frame + 1) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) frame->count)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) if (WaitTillCardIsFree(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) goto errrelfw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) outw(0xf0, base); /* start upload sequence */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) outw(0x00, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) outw(frame->addr, base); /* lsb of address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) word_count = frame->count / 2 + frame->count % 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) outw(word_count, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) udelay(100); /* 0x2f */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) if (WaitTillCardIsFree(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) goto errrelfw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) status = inw(base + 0x4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) if (status != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) dev_warn(&pdev->dev, "Card%d rejected load header:\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) "Address:0x%x\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) "Count:0x%x\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) "Status:0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) index + 1, frame->addr, frame->count, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) goto errrelfw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) outsw(base, frame->data, word_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) udelay(50); /* 0x0f */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) if (WaitTillCardIsFree(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) goto errrelfw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) status = inw(base + 0x4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) if (status != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) dev_err(&pdev->dev, "Card%d got out of sync.Card "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) "Status:0x%x\n", index + 1, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) goto errrelfw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) /* XXX: should we test it by reading it back and comparing with original like
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) * in load firmware package? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) for (frame = (struct stframe *)fw->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) frame < (struct stframe *)(fw->data + fw->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) frame = (struct stframe *)((u8 *)(frame + 1) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) frame->count)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) if (WaitTillCardIsFree(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) goto errrelfw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) outw(0xf1, base); /* start download sequence */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) outw(0x00, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) outw(frame->addr, base); /* lsb of address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) word_count = (frame->count >> 1) + frame->count % 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) outw(word_count + 1, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) udelay(50); /* 0xf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) if (WaitTillCardIsFree(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) goto errrelfw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) status = inw(base + 0x4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) if (status != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) "Address:0x%x\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) "Count:0x%x\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) "Status: 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) index + 1, frame->addr, frame->count, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) goto errrelfw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) data = kmalloc_array(word_count, 2, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) if (data == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) dev_err(&pdev->dev, "Card%d, firmware upload "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) "failed, not enough memory\n", index + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) goto errrelfw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) inw(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) insw(base, data, word_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) for (a = 0; a < frame->count; a++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) if (data[a] != frame->data[a]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) kfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) dev_err(&pdev->dev, "Card%d, firmware upload "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) "failed\n", index + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) goto errrelfw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) kfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) udelay(50); /* 0xf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) if (WaitTillCardIsFree(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) goto errrelfw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) status = inw(base + 0x4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) if (status != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) dev_err(&pdev->dev, "Card%d verify got out of sync. "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) "Card Status:0x%x\n", index + 1, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) goto errrelfw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) /* xfer ctrl */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) if (WaitTillCardIsFree(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) goto errrelfw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) outw(0xf2, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) outw(0x800, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) outw(0x0, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) outw(0x0, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) InterruptTheCard(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) outw(0x0, base + 0x4); /* for ISI4608 cards */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) board->status |= FIRMWARE_LOADED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) errrelfw:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) release_firmware(fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) end:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) * Insmod can set static symbols so keep these static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) static unsigned int card_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) static int isicom_probe(struct pci_dev *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) const struct pci_device_id *ent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) unsigned int signature, index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) int retval = -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) struct isi_board *board = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) if (card_count >= BOARD_COUNT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) retval = pci_enable_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) dev_err(&pdev->dev, "failed to enable\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) /* allot the first empty slot in the array */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) for (index = 0; index < BOARD_COUNT; index++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) if (isi_card[index].base == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) board = &isi_card[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) if (index == BOARD_COUNT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) goto err_disable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) board->index = index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) board->base = pci_resource_start(pdev, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) board->irq = pdev->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) card_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) pci_set_drvdata(pdev, board);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) retval = pci_request_region(pdev, 3, ISICOM_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) dev_err(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) "will be disabled.\n", board->base, board->base + 15,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) index + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) retval = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) goto errdec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) retval = request_irq(board->irq, isicom_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) IRQF_SHARED, ISICOM_NAME, board);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) if (retval < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) dev_err(&pdev->dev, "Could not install handler at Irq %d. "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) "Card%d will be disabled.\n", board->irq, index + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) goto errunrr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) retval = reset_card(pdev, index, &signature);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) if (retval < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) goto errunri;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) retval = load_firmware(pdev, index, signature);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) if (retval < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) goto errunri;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) for (index = 0; index < board->port_count; index++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) struct tty_port *tport = &board->ports[index].port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) tty_port_init(tport);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) tport->ops = &isicom_port_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) tport->close_delay = 50 * HZ/100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) tport->closing_wait = 3000 * HZ/100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) tty_port_register_device(tport, isicom_normal,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) board->index * 16 + index, &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) errunri:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) free_irq(board->irq, board);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) errunrr:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) pci_release_region(pdev, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) errdec:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) board->base = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) card_count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) err_disable:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) pci_disable_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) static void isicom_remove(struct pci_dev *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) struct isi_board *board = pci_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) for (i = 0; i < board->port_count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) tty_unregister_device(isicom_normal, board->index * 16 + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) tty_port_destroy(&board->ports[i].port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) free_irq(board->irq, board);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) pci_release_region(pdev, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) board->base = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) card_count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) pci_disable_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) static int __init isicom_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) int retval, idx, channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) struct isi_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) for (idx = 0; idx < BOARD_COUNT; idx++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) port = &isi_ports[idx * 16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) isi_card[idx].ports = port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) spin_lock_init(&isi_card[idx].card_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) for (channel = 0; channel < 16; channel++, port++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) port->magic = ISICOM_MAGIC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) port->card = &isi_card[idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) port->channel = channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) port->status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) /* . . . */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) isi_card[idx].base = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) isi_card[idx].irq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) /* tty driver structure initialization */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) isicom_normal = alloc_tty_driver(PORT_COUNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) if (!isicom_normal) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) isicom_normal->name = "ttyM";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) isicom_normal->major = ISICOM_NMAJOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) isicom_normal->minor_start = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) isicom_normal->type = TTY_DRIVER_TYPE_SERIAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) isicom_normal->subtype = SERIAL_TYPE_NORMAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) isicom_normal->init_termios = tty_std_termios;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) CLOCAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) isicom_normal->flags = TTY_DRIVER_REAL_RAW |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) tty_set_operations(isicom_normal, &isicom_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) retval = tty_register_driver(isicom_normal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) pr_debug("Couldn't register the dialin driver\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) goto err_puttty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) retval = pci_register_driver(&isicom_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664) if (retval < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) pr_err("Unable to register pci driver.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) goto err_unrtty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) mod_timer(&tx, jiffies + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) err_unrtty:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) tty_unregister_driver(isicom_normal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) err_puttty:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) put_tty_driver(isicom_normal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) static void __exit isicom_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) del_timer_sync(&tx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) pci_unregister_driver(&isicom_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) tty_unregister_driver(isicom_normal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) put_tty_driver(isicom_normal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) module_init(isicom_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) module_exit(isicom_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) MODULE_AUTHOR("MultiTech");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) MODULE_FIRMWARE("isi608.bin");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) MODULE_FIRMWARE("isi608em.bin");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) MODULE_FIRMWARE("isi616em.bin");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) MODULE_FIRMWARE("isi4608.bin");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) MODULE_FIRMWARE("isi4616.bin");