nozomi.c revision 716da631ae91fc5e9f8d5815f8ef5fbfed862b80
120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * nozomi.c -- HSDPA driver Broadband Wireless Data Card - Globe Trotter 320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Written by: Ulf Jakobsson, 5e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel * Jan Åkerfeldt, 620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Stefan Thomasson, 720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Maintained by: Paul Hardwick (p.hardwick@option.com) 920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 1020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Patches: 1120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Locking code changes for Vodafone by Sphere Systems Ltd, 1220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Andrew Bird (ajb@spheresystems.co.uk ) 1320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * & Phil Sanderson 1420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 1520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Source has been ported from an implementation made by Filip Aben @ Option 1620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 1720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -------------------------------------------------------------------------- 1820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 1920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Copyright (c) 2005,2006 Option Wireless Sweden AB 2020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Copyright (c) 2006 Sphere Systems Ltd 2120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Copyright (c) 2006 Option Wireless n/v 2220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * All rights Reserved. 2320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 2420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * This program is free software; you can redistribute it and/or modify 2520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * it under the terms of the GNU General Public License as published by 2620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * the Free Software Foundation; either version 2 of the License, or 2720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * (at your option) any later version. 2820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 2920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * This program is distributed in the hope that it will be useful, 3020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * but WITHOUT ANY WARRANTY; without even the implied warranty of 3120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 3220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * GNU General Public License for more details. 3320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 3420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * You should have received a copy of the GNU General Public License 3520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * along with this program; if not, write to the Free Software 3620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 3720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 3820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -------------------------------------------------------------------------- 3920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 4020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 4120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Enable this to have a lot of debug printouts */ 4220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DEBUG 4320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 4420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/kernel.h> 4520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/module.h> 4620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/pci.h> 4720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/ioport.h> 4820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/tty.h> 4920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/tty_driver.h> 5020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/tty_flip.h> 5120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/serial.h> 5220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/interrupt.h> 5320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/kmod.h> 5420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/init.h> 5520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/kfifo.h> 5620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/uaccess.h> 5720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <asm/byteorder.h> 5820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 5920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/delay.h> 6020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 6120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 6220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define VERSION_STRING DRIVER_DESC " 2.1d (build date: " \ 6320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel __DATE__ " " __TIME__ ")" 6420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 6520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Macros definitions */ 6620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 6720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Default debug printout level */ 6820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_DEBUG_LEVEL 0x00 6920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 7020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define P_BUF_SIZE 128 7120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NFO(_err_flag_, args...) \ 7220fd1e3bea554620d489f3542496639c1babe0b3Frank Seideldo { \ 7320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char tmp[P_BUF_SIZE]; \ 7420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel snprintf(tmp, sizeof(tmp), ##args); \ 7520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(_err_flag_ "[%d] %s(): %s\n", __LINE__, \ 76bf9d89295233ae2ba7b312c78ee5657307b09f4cHarvey Harrison __func__, tmp); \ 7720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} while (0) 7820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 7920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG1(args...) D_(0x01, ##args) 8020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG2(args...) D_(0x02, ##args) 8120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG3(args...) D_(0x04, ##args) 8220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG4(args...) D_(0x08, ##args) 8320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG5(args...) D_(0x10, ##args) 8420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG6(args...) D_(0x20, ##args) 8520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG7(args...) D_(0x40, ##args) 8620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG8(args...) D_(0x80, ##args) 8720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 8820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef DEBUG 8920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Do we need this settable at runtime? */ 9020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int debug = NOZOMI_DEBUG_LEVEL; 9120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 92e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel#define D(lvl, args...) do \ 93e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \ 94e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel while (0) 9520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define D_(lvl, args...) D(lvl, ##args) 9620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 9720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* These printouts are always printed */ 9820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 9920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#else 10020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int debug; 10120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define D_(lvl, args...) 10220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 10320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 10420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* TODO: rewrite to optimize macros... */ 10520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 10620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define TMP_BUF_MAX 256 10720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 10820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DUMP(buf__,len__) \ 10920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel do { \ 11020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char tbuf[TMP_BUF_MAX] = {0};\ 11120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (len__ > 1) {\ 11220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel snprintf(tbuf, len__ > TMP_BUF_MAX ? TMP_BUF_MAX : len__, "%s", buf__);\ 11320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (tbuf[len__-2] == '\r') {\ 11420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tbuf[len__-2] = 'r';\ 11520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } \ 11620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("SENDING: '%s' (%d+n)", tbuf, len__);\ 11720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else {\ 11820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("SENDING: '%s' (%d)", tbuf, len__);\ 11920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } \ 12020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} while (0) 12120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 12220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Defines */ 12320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_NAME "nozomi" 12420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_NAME_TTY "nozomi_tty" 12520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DRIVER_DESC "Nozomi driver" 12620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 12720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NTTY_TTY_MAXMINORS 256 12820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NTTY_FIFO_BUFFER_SIZE 8192 12920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Must be power of 2 */ 13120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define FIFO_BUFFER_SIZE_UL 8192 13220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Size of tmp send buffer to card */ 13420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define SEND_BUF_MAX 1024 13520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define RECEIVE_BUF_MAX 4 13620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Define all types of vendors and devices to support */ 13920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define VENDOR1 0x1931 /* Vendor Option */ 14020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DEVICE1 0x000c /* HSDPA card */ 14120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define R_IIR 0x0000 /* Interrupt Identity Register */ 14320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define R_FCR 0x0000 /* Flow Control Register */ 14420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define R_IER 0x0004 /* Interrupt Enable Register */ 14520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CONFIG_MAGIC 0xEFEFFEFE 14720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define TOGGLE_VALID 0x0000 14820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Definition of interrupt tokens */ 15020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_DL1 0x0001 15120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_UL1 0x0002 15220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_DL2 0x0004 15320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_UL2 0x0008 15420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_DL1 0x0010 15520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_DL2 0x0020 15620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_UL 0x0040 15720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP1_DL 0x0080 15820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP1_UL 0x0100 15920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP2_DL 0x0200 16020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP2_UL 0x0400 16120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DL 0x0800 16220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_UL 0x1000 16320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define RESET 0x8000 16420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 16520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_DL (MDM_DL1 | MDM_DL2) 16620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_UL (MDM_UL1 | MDM_UL2) 16720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_DL (DIAG_DL1 | DIAG_DL2) 16820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 16920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* modem signal definition */ 17020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DSR 0x0001 17120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DCD 0x0002 17220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_RI 0x0004 17320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_CTS 0x0008 17420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 17520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DTR 0x0001 17620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_RTS 0x0002 17720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 17820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MAX_PORT 4 17920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_MAX_PORTS 5 18020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_MAX_CARDS (NTTY_TTY_MAXMINORS / MAX_PORT) 18120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 18220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Type definitions */ 18320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 18420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 18520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * There are two types of nozomi cards, 18620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * one with 2048 memory and with 8192 memory 18720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 18820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum card_type { 18920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel F32_2 = 2048, /* 512 bytes downlink + uplink * 2 -> 2048 */ 19020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel F32_8 = 8192, /* 3072 bytes downl. + 1024 bytes uplink * 2 -> 8192 */ 19120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 19220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 193661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel/* Initialization states a card can be in */ 194661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidelenum card_state { 195661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_UKNOWN = 0, 196661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_ENABLED = 1, /* pci device enabled */ 197661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_ALLOCATED = 2, /* config setup done */ 198661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_READY = 3, /* flowcontrols received */ 199661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel}; 200661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 20120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Two different toggle channels exist */ 20220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum channel_type { 20320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CH_A = 0, 20420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CH_B = 1, 20520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 20620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 20720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Port definition for the card regarding flow control */ 20820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum ctrl_port_type { 20920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_CMD = 0, 21020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_MDM = 1, 21120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_DIAG = 2, 21220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_APP1 = 3, 21320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_APP2 = 4, 21420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_ERROR = -1, 21520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 21620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 21720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Ports that the nozomi has */ 21820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum port_type { 21920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_MDM = 0, 22020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_DIAG = 1, 22120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_APP1 = 2, 22220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_APP2 = 3, 22320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_CTRL = 4, 22420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_ERROR = -1, 22520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 22620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 22720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef __BIG_ENDIAN 22820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Big endian */ 22920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 23020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct toggles { 231e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int enabled:5; /* 23220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Toggle fields are valid if enabled is 0, 23320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * else A-channels must always be used. 23420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 235e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int diag_dl:1; 236e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_dl:1; 237e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_ul:1; 23820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 23920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 24020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Configuration table to read at startup of card */ 24120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Is for now only needed during initialization phase */ 24220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct config_table { 24320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 signature; 24420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 product_information; 24520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 version; 24620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad3[3]; 24720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct toggles toggle; 24820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad1[4]; 24920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len1; /* 25020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * If this is 64, it can hold 25120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 60 bytes + 4 that is length field 25220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 25320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_start; 25420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 25520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len1; 25620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len2; /* 25720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * If this is 64, it can hold 25820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 60 bytes + 4 that is length field 25920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 26020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app1_len; 26120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 26220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len2; 26320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_ctrl_len; 26420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app2_len; 26520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad2[16]; 26620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len1; 26720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_start; 26820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_diag_len; 26920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len2; 27020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app1_len; 27120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app2_len; 27220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_ctrl_len; 27320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 27420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 27520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control downlink flags */ 27620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_dl { 27720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 278e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserved:4; 279e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int CTS:1; 280e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RI:1; 281e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DCD:1; 282e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DSR:1; 28320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 28420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 28520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control uplink flags */ 28620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_ul { 28720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 288e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserved:6; 289e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RTS:1; 290e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DTR:1; 29120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 29220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 29320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#else 29420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Little endian */ 29520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 29620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This represents the toggle information */ 29720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct toggles { 298e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_ul:1; 299e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_dl:1; 300e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int diag_dl:1; 301e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int enabled:5; /* 30220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Toggle fields are valid if enabled is 0, 30320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * else A-channels must always be used. 30420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 30520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 30620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 30720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Configuration table to read at startup of card */ 30820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct config_table { 30920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 signature; 31020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 version; 31120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 product_information; 31220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct toggles toggle; 31320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad1[7]; 31420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_start; 31520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len1; /* 31620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * If this is 64, it can hold 31720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 60 bytes + 4 that is length field 31820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 31920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len2; 32020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len1; 32120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len2; 32220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app1_len; 32320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app2_len; 32420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_ctrl_len; 32520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad2[16]; 32620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_start; 32720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len2; 32820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len1; 32920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_diag_len; 33020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app1_len; 33120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app2_len; 33220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_ctrl_len; 33320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 33420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 33520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control downlink flags */ 33620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_dl { 337e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DSR:1; 338e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DCD:1; 339e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RI:1; 340e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int CTS:1; 341e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserverd:4; 34220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 34320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 34420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 34520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control uplink flags */ 34620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_ul { 347e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DTR:1; 348e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RTS:1; 349e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserved:6; 35020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 35120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 35220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 35320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 35420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This holds all information that is needed regarding a port */ 35520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct port { 35620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 update_flow_control; 35720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_ul ctrl_ul; 35820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_dl ctrl_dl; 35920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct kfifo *fifo_ul; 36020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *dl_addr[2]; 36120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 dl_size[2]; 36220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 toggle_dl; 36320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *ul_addr[2]; 36420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 ul_size[2]; 36520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 toggle_ul; 36620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 token_dl; 36720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 36820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct tty_struct *tty; 36920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int tty_open_count; 37020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* mutex to ensure one access patch to this port */ 37120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct mutex tty_sem; 37220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel wait_queue_head_t tty_wait; 37320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct async_icount tty_icount; 37420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 37520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 37620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Private data one for each card in the system */ 37720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct nozomi { 37820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *base_addr; 37920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flip; 38020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 38120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Pointers to registers */ 38220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *reg_iir; 38320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *reg_fcr; 38420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *reg_ier; 38520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 38620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 last_ier; 38720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enum card_type card_type; 38820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct config_table config_table; /* Configuration table */ 38920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct pci_dev *pdev; 39020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port port[NOZOMI_MAX_PORTS]; 39120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 *send_buf; 39220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 39320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spinlock_t spin_mutex; /* secures access to registers and tty */ 39420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 39520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int index_start; 396661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel enum card_state state; 39720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 open_ttys; 39820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 39920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 40020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This is a data packet that is read or written to/from card */ 40120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct buffer { 40220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size; /* size is the length of the data buffer */ 40320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 *data; 40420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 40520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 40620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Global variables */ 40718bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidelstatic const struct pci_device_id nozomi_pci_tbl[] __devinitconst = { 40820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel {PCI_DEVICE(VENDOR1, DEVICE1)}, 40920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel {}, 41020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 41120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 41220fd1e3bea554620d489f3542496639c1babe0b3Frank SeidelMODULE_DEVICE_TABLE(pci, nozomi_pci_tbl); 41320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 41420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic struct nozomi *ndevs[NOZOMI_MAX_CARDS]; 41520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic struct tty_driver *ntty_driver; 41620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 41720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 41820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * find card by tty_index 41920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 42020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic inline struct nozomi *get_dc_by_tty(const struct tty_struct *tty) 42120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 42220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return tty ? ndevs[tty->index / MAX_PORT] : NULL; 42320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 42420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 42520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic inline struct port *get_port_by_tty(const struct tty_struct *tty) 42620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 42720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *ndev = get_dc_by_tty(tty); 42820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ndev ? &ndev->port[tty->index % MAX_PORT] : NULL; 42920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 43020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 43120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 43220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * TODO: 43320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -Optimize 43420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -Rewrite cleaner 43520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 43620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 43720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void read_mem32(u32 *buf, const void __iomem *mem_addr_start, 43820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size_bytes) 43920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 44020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 i = 0; 441782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro const u32 __iomem *ptr = mem_addr_start; 44220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 *buf16; 44320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 44420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!ptr || !buf)) 44520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto out; 44620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 44720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* shortcut for extremely often used cases */ 44820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (size_bytes) { 44920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 2: /* 2 bytes */ 45020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel buf16 = (u16 *) buf; 451782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro *buf16 = __le16_to_cpu(readw(ptr)); 45220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto out; 45320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 45420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 4: /* 4 bytes */ 455782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro *(buf) = __le32_to_cpu(readl(ptr)); 45620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto out; 45720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 45820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 45920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 46020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel while (i < size_bytes) { 46120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (size_bytes - i == 2) { 46220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Handle 2 bytes in the end */ 46320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel buf16 = (u16 *) buf; 464782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro *(buf16) = __le16_to_cpu(readw(ptr)); 46520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i += 2; 46620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 46720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Read 4 bytes */ 468782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro *(buf) = __le32_to_cpu(readl(ptr)); 46920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i += 4; 47020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 47120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel buf++; 47220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ptr++; 47320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 47420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelout: 47520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return; 47620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 47720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 47820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 47920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * TODO: 48020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -Optimize 48120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -Rewrite cleaner 48220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 48371e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardtstatic u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf, 48420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size_bytes) 48520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 48620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 i = 0; 487782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro u32 __iomem *ptr = mem_addr_start; 48871e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const u16 *buf16; 48920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 49020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!ptr || !buf)) 49120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 49220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 49320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* shortcut for extremely often used cases */ 49420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (size_bytes) { 49520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 2: /* 2 bytes */ 49671e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt buf16 = (const u16 *)buf; 497782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro writew(__cpu_to_le16(*buf16), ptr); 49820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 2; 49920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 50020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 1: /* 50120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * also needs to write 4 bytes in this case 50220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * so falling through.. 50320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 50420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 4: /* 4 bytes */ 505782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro writel(__cpu_to_le32(*buf), ptr); 50620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 4; 50720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 50820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 50920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 51020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel while (i < size_bytes) { 51120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (size_bytes - i == 2) { 51220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 2 bytes */ 51371e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt buf16 = (const u16 *)buf; 514782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro writew(__cpu_to_le16(*buf16), ptr); 51520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i += 2; 51620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 51720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 4 bytes */ 518782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro writel(__cpu_to_le32(*buf), ptr); 51920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i += 4; 52020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 52120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel buf++; 52220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ptr++; 52320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 52420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return i; 52520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 52620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 52720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Setup pointers to different channels and also setup buffer sizes. */ 52820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void setup_memory(struct nozomi *dc) 52920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 53020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *offset = dc->base_addr + dc->config_table.dl_start; 53120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* The length reported is including the length field of 4 bytes, 53220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * hence subtract with 4. 53320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 53420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel const u16 buff_offset = 4; 53520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 53620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Modem port dl configuration */ 53720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].dl_addr[CH_A] = offset; 53820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].dl_addr[CH_B] = 53920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_mdm_len1); 54020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].dl_size[CH_A] = 54120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_mdm_len1 - buff_offset; 54220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].dl_size[CH_B] = 54320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_mdm_len2 - buff_offset; 54420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 54520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Diag port dl configuration */ 54620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].dl_addr[CH_A] = 54720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_mdm_len2); 54820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].dl_size[CH_A] = 54920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_diag_len1 - buff_offset; 55020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].dl_addr[CH_B] = 55120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_diag_len1); 55220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].dl_size[CH_B] = 55320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_diag_len2 - buff_offset; 55420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 55520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* App1 port dl configuration */ 55620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].dl_addr[CH_A] = 55720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_diag_len2); 55820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].dl_size[CH_A] = 55920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_app1_len - buff_offset; 56020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 56120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* App2 port dl configuration */ 56220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].dl_addr[CH_A] = 56320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_app1_len); 56420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].dl_size[CH_A] = 56520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_app2_len - buff_offset; 56620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 56720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Ctrl dl configuration */ 56820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_CTRL].dl_addr[CH_A] = 56920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_app2_len); 57020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_CTRL].dl_size[CH_A] = 57120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_ctrl_len - buff_offset; 57220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 57320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel offset = dc->base_addr + dc->config_table.ul_start; 57420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 57520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Modem Port ul configuration */ 57620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].ul_addr[CH_A] = offset; 57720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].ul_size[CH_A] = 57820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_mdm_len1 - buff_offset; 57920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].ul_addr[CH_B] = 58020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_mdm_len1); 58120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].ul_size[CH_B] = 58220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_mdm_len2 - buff_offset; 58320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 58420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Diag port ul configuration */ 58520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].ul_addr[CH_A] = 58620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_mdm_len2); 58720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].ul_size[CH_A] = 58820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_diag_len - buff_offset; 58920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 59020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* App1 port ul configuration */ 59120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].ul_addr[CH_A] = 59220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_diag_len); 59320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].ul_size[CH_A] = 59420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_app1_len - buff_offset; 59520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 59620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* App2 port ul configuration */ 59720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].ul_addr[CH_A] = 59820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_app1_len); 59920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].ul_size[CH_A] = 60020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_app2_len - buff_offset; 60120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 60220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Ctrl ul configuration */ 60320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_CTRL].ul_addr[CH_A] = 60420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_app2_len); 60520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_CTRL].ul_size[CH_A] = 60620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_ctrl_len - buff_offset; 60720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 60820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 60920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Dump config table under initalization phase */ 61020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef DEBUG 61120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void dump_table(const struct nozomi *dc) 61220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 61320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("signature: 0x%08X", dc->config_table.signature); 61420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("version: 0x%04X", dc->config_table.version); 61520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("product_information: 0x%04X", \ 61620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.product_information); 61720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("toggle enabled: %d", dc->config_table.toggle.enabled); 61820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("toggle up_mdm: %d", dc->config_table.toggle.mdm_ul); 61920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("toggle dl_mdm: %d", dc->config_table.toggle.mdm_dl); 62020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("toggle dl_dbg: %d", dc->config_table.toggle.diag_dl); 62120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 62220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_start: 0x%04X", dc->config_table.dl_start); 62320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_mdm_len0: 0x%04X, %d", dc->config_table.dl_mdm_len1, 62420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_mdm_len1); 62520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_mdm_len1: 0x%04X, %d", dc->config_table.dl_mdm_len2, 62620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_mdm_len2); 62720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_diag_len0: 0x%04X, %d", dc->config_table.dl_diag_len1, 62820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_diag_len1); 62920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_diag_len1: 0x%04X, %d", dc->config_table.dl_diag_len2, 63020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_diag_len2); 63120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_app1_len: 0x%04X, %d", dc->config_table.dl_app1_len, 63220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_app1_len); 63320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_app2_len: 0x%04X, %d", dc->config_table.dl_app2_len, 63420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_app2_len); 63520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_ctrl_len: 0x%04X, %d", dc->config_table.dl_ctrl_len, 63620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_ctrl_len); 63720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_start: 0x%04X, %d", dc->config_table.ul_start, 63820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_start); 63920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_mdm_len[0]: 0x%04X, %d", dc->config_table.ul_mdm_len1, 64020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_mdm_len1); 64120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_mdm_len[1]: 0x%04X, %d", dc->config_table.ul_mdm_len2, 64220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_mdm_len2); 64320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_diag_len: 0x%04X, %d", dc->config_table.ul_diag_len, 64420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_diag_len); 64520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_app1_len: 0x%04X, %d", dc->config_table.ul_app1_len, 64620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_app1_len); 64720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_app2_len: 0x%04X, %d", dc->config_table.ul_app2_len, 64820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_app2_len); 64920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_ctrl_len: 0x%04X, %d", dc->config_table.ul_ctrl_len, 65020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_ctrl_len); 65120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 65220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#else 653e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidelstatic inline void dump_table(const struct nozomi *dc) { } 65420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 65520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 65620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 65720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Read configuration table from card under intalization phase 65820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Returns 1 if ok, else 0 65920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 66020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int nozomi_read_config_table(struct nozomi *dc) 66120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 66220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_mem32((u32 *) &dc->config_table, dc->base_addr + 0, 66320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel sizeof(struct config_table)); 66420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 66520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (dc->config_table.signature != CONFIG_MAGIC) { 66620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "ConfigTable Bad! 0x%08X != 0x%08X\n", 66720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.signature, CONFIG_MAGIC); 66820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 66920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 67020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 67120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if ((dc->config_table.version == 0) 67220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel || (dc->config_table.toggle.enabled == TOGGLE_VALID)) { 67320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 67420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Second phase, configuring card"); 67520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 67620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel setup_memory(dc); 67720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 67820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].toggle_ul = dc->config_table.toggle.mdm_ul; 67920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].toggle_dl = dc->config_table.toggle.mdm_dl; 68020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].toggle_dl = dc->config_table.toggle.diag_dl; 68120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("toggle ports: MDM UL:%d MDM DL:%d, DIAG DL:%d", 68220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].toggle_ul, 68320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].toggle_dl, dc->port[PORT_DIAG].toggle_dl); 68420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 68520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dump_table(dc); 68620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 68720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = PORT_MDM; i < MAX_PORT; i++) { 68820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[i].fifo_ul = 68920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfifo_alloc(FIFO_BUFFER_SIZE_UL, GFP_ATOMIC, NULL); 69020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel memset(&dc->port[i].ctrl_dl, 0, sizeof(struct ctrl_dl)); 69120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel memset(&dc->port[i].ctrl_ul, 0, sizeof(struct ctrl_ul)); 69220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 69320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 69420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Enable control channel */ 69520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | CTRL_DL; 69620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 69720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 698661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->state = NOZOMI_STATE_ALLOCATED; 69920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_info(&dc->pdev->dev, "Initialization OK!\n"); 70020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 70120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 70220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 70320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if ((dc->config_table.version > 0) 70420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel && (dc->config_table.toggle.enabled != TOGGLE_VALID)) { 70520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 offset = 0; 70620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("First phase: pushing upload buffers, clearing download"); 70720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 70820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_info(&dc->pdev->dev, "Version of card: %d\n", 70920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.version); 71020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 71120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Here we should disable all I/O over F32. */ 71220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel setup_memory(dc); 71320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 71420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 71520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * We should send ALL channel pair tokens back along 71620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * with reset token 71720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 71820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 71920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* push upload modem buffers */ 72020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_MDM].ul_addr[CH_A], 72120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (u32 *) &offset, 4); 72220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_MDM].ul_addr[CH_B], 72320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (u32 *) &offset, 4); 72420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 72520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL | DIAG_DL | MDM_DL, dc->reg_fcr); 72620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 72720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("First phase done"); 72820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 72920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 73020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 73120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 73220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 73320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Enable uplink interrupts */ 73420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void enable_transmit_ul(enum port_type port, struct nozomi *dc) 73520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 73671e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL}; 73720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 73820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 73920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier |= mask[port]; 74020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 74120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 74220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 74320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 74420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 74520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 74620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Disable uplink interrupts */ 74720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void disable_transmit_ul(enum port_type port, struct nozomi *dc) 74820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 74971e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = 75071e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL}; 75120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 75220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 75320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= mask[port]; 75420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 75520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 75620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 75720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 75820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 75920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 76020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Enable downlink interrupts */ 76120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void enable_transmit_dl(enum port_type port, struct nozomi *dc) 76220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 76371e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL}; 76420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 76520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 76620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier |= mask[port]; 76720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 76820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 76920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 77020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 77120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 77220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 77320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Disable downlink interrupts */ 77420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void disable_transmit_dl(enum port_type port, struct nozomi *dc) 77520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 77671e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = 77771e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL}; 77820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 77920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 78020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= mask[port]; 78120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 78220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 78320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 78420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 78520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 78620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 78720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 78820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - send buffer to card and ack. 78920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - don't ack, don't send buffer to card. 79020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 79118bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidelstatic int send_data(enum port_type index, const struct nozomi *dc) 79220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 79320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size = 0; 79471e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct port *port = &dc->port[index]; 79518bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const u8 toggle = port->toggle_ul; 79620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *addr = port->ul_addr[toggle]; 79718bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const u32 ul_size = port->ul_size[toggle]; 79820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct tty_struct *tty = port->tty; 79920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 80020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Get data from tty and place in buf for now */ 80120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel size = __kfifo_get(port->fifo_ul, dc->send_buf, 80220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ul_size < SEND_BUF_MAX ? ul_size : SEND_BUF_MAX); 80320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 80420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (size == 0) { 80520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG4("No more data to send, disable link:"); 80620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 80720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 80820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 80920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* DUMP(buf, size); */ 81020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 81120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Write length + data */ 81220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(addr, (u32 *) &size, 4); 81320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(addr + 4, (u32 *) dc->send_buf, size); 81420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 81520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (tty) 81620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_wakeup(tty); 81720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 81820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 81920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 82020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 82120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* If all data has been read, return 1, else 0 */ 82220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int receive_data(enum port_type index, struct nozomi *dc) 82320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 82420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 buf[RECEIVE_BUF_MAX] = { 0 }; 82520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int size; 82620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 offset = 4; 82720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = &dc->port[index]; 82820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *addr = port->dl_addr[port->toggle_dl]; 82920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct tty_struct *tty = port->tty; 83020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 83120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 83220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!tty)) { 83320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("tty not open for port: %d?", index); 83420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 83520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 83620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 83720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_mem32((u32 *) &size, addr, 4); 83820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* DBG1( "%d bytes port: %d", size, index); */ 83920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 84020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (test_bit(TTY_THROTTLED, &tty->flags)) { 84120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("No room in tty, don't read data, don't ack interrupt, " 84220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "disable interrupt"); 84320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 84420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* disable interrupt in downlink... */ 84520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel disable_transmit_dl(index, dc); 84620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 84720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 84820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 84920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(size == 0)) { 85020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "size == 0?\n"); 85120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 85220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 85320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 85420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_buffer_request_room(tty, size); 85520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 85620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel while (size > 0) { 85720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_mem32((u32 *) buf, addr + offset, RECEIVE_BUF_MAX); 85820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 85920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (size == 1) { 86020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_insert_flip_char(tty, buf[0], TTY_NORMAL); 86120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel size = 0; 86220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (size < RECEIVE_BUF_MAX) { 86320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel size -= tty_insert_flip_string(tty, (char *) buf, size); 86420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 86520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i = tty_insert_flip_string(tty, \ 86620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (char *) buf, RECEIVE_BUF_MAX); 86720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel size -= i; 86820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel offset += i; 86920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 87020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 87120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 87220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_bit(index, &dc->flip); 87320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 87420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 87520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 87620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 87720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Debug for interrupts */ 87820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef DEBUG 87920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic char *interrupt2str(u16 interrupt) 88020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 88120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel static char buf[TMP_BUF_MAX]; 88220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char *p = buf; 88320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 88420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_DL1 ? p += snprintf(p, TMP_BUF_MAX, "MDM_DL1 ") : NULL; 88520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 88620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "MDM_DL2 ") : NULL; 88720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 88820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_UL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 88920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "MDM_UL1 ") : NULL; 89020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_UL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "MDM_UL2 ") : NULL; 89220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 89320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & DIAG_DL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "DIAG_DL1 ") : NULL; 89520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & DIAG_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "DIAG_DL2 ") : NULL; 89720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 89820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & DIAG_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "DIAG_UL ") : NULL; 90020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 90120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP1_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP1_DL ") : NULL; 90320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP2_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP2_DL ") : NULL; 90520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 90620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP1_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP1_UL ") : NULL; 90820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP2_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP2_UL ") : NULL; 91020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 91120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & CTRL_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 91220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "CTRL_DL ") : NULL; 91320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & CTRL_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 91420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "CTRL_UL ") : NULL; 91520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 91620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & RESET ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 91720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "RESET ") : NULL; 91820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 91920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return buf; 92020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 92120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 92220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 92320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 92420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Receive flow control 92520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - If ok, else 0 92620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 92720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int receive_flow_control(struct nozomi *dc) 92820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 92920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enum port_type port = PORT_MDM; 93020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_dl ctrl_dl; 93120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_dl old_ctrl; 93220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 enable_ier = 0; 93320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 93420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_mem32((u32 *) &ctrl_dl, dc->port[PORT_CTRL].dl_addr[CH_A], 2); 93520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 93620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (ctrl_dl.port) { 93720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_CMD: 93820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("The Base Band sends this value as a response to a " 93920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "request for IMSI detach sent over the control " 94020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "channel uplink (see section 7.6.1)."); 94120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 94220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_MDM: 94320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_MDM; 94420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = MDM_DL; 94520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 94620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_DIAG: 94720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_DIAG; 94820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = DIAG_DL; 94920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 95020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_APP1: 95120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_APP1; 95220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = APP1_DL; 95320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 95420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_APP2: 95520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_APP2; 95620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = APP2_DL; 957661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel if (dc->state == NOZOMI_STATE_ALLOCATED) { 958661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel /* 959661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel * After card initialization the flow control 960661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel * received for APP2 is always the last 961661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel */ 962661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->state = NOZOMI_STATE_READY; 963661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dev_info(&dc->pdev->dev, "Device READY!\n"); 964661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel } 96520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 96620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel default: 96720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 96820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "ERROR: flow control received for non-existing port\n"); 96920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 97020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel }; 97120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 97220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("0x%04X->0x%04X", *((u16 *)&dc->port[port].ctrl_dl), 97320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *((u16 *)&ctrl_dl)); 97420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 97520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel old_ctrl = dc->port[port].ctrl_dl; 97620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].ctrl_dl = ctrl_dl; 97720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 97820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.CTS == 1 && ctrl_dl.CTS == 0) { 97920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Disable interrupt (0x%04X) on port: %d", 98020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier, port); 98120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel disable_transmit_ul(port, dc); 98220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 98320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (old_ctrl.CTS == 0 && ctrl_dl.CTS == 1) { 98420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 98520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (__kfifo_len(dc->port[port].fifo_ul)) { 98620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Enable interrupt (0x%04X) on port: %d", 98720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier, port); 98820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Data in buffer [%d], enable transmit! ", 98920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel __kfifo_len(dc->port[port].fifo_ul)); 99020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(port, dc); 99120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 99220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("No data in buffer..."); 99320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 99420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 99520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 99620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (*(u16 *)&old_ctrl == *(u16 *)&ctrl_dl) { 99720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1(" No change in mctrl"); 99820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 99920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 100020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Update statistics */ 100120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.CTS != ctrl_dl.CTS) 100220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.cts++; 100320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.DSR != ctrl_dl.DSR) 100420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.dsr++; 100520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.RI != ctrl_dl.RI) 100620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.rng++; 100720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.DCD != ctrl_dl.DCD) 100820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.dcd++; 100920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 101020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel wake_up_interruptible(&dc->port[port].tty_wait); 101120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 101220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("port: %d DCD(%d), CTS(%d), RI(%d), DSR(%d)", 101320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port, 101420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.dcd, dc->port[port].tty_icount.cts, 101520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.rng, dc->port[port].tty_icount.dsr); 101620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 101720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 101820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 101920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 102020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic enum ctrl_port_type port2ctrl(enum port_type port, 102120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel const struct nozomi *dc) 102220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 102320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (port) { 102420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_MDM: 102520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_MDM; 102620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_DIAG: 102720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_DIAG; 102820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_APP1: 102920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_APP1; 103020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_APP2: 103120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_APP2; 103220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel default: 103320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 103420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "ERROR: send flow control " \ 103520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "received for non-existing port\n"); 103620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel }; 103720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_ERROR; 103820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 103920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 104020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 104120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Send flow control, can only update one channel at a time 104220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - If we have updated all flow control 104320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - If we need to update more flow control, ack current enable more 104420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 104520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int send_flow_control(struct nozomi *dc) 104620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 104720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 i, more_flow_control_to_be_updated = 0; 104820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 *ctrl; 104920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 105020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = PORT_MDM; i < MAX_PORT; i++) { 105120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (dc->port[i].update_flow_control) { 105220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (more_flow_control_to_be_updated) { 105320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* We have more flow control to be updated */ 105420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 105520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 105620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[i].ctrl_ul.port = port2ctrl(i, dc); 105720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl = (u16 *)&dc->port[i].ctrl_ul; 105820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_CTRL].ul_addr[0], \ 105920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (u32 *) ctrl, 2); 106020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[i].update_flow_control = 0; 106120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel more_flow_control_to_be_updated = 1; 106220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 106320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 106420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 106520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 106620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 106720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 1068e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel * Handle downlink data, ports that are handled are modem and diagnostics 106920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - ok 107020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - toggle fields are out of sync 107120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 107220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int handle_data_dl(struct nozomi *dc, enum port_type port, u8 *toggle, 107320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 read_iir, u16 mask1, u16 mask2) 107420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 107520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (*toggle == 0 && read_iir & mask1) { 107620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 107720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask1, dc->reg_fcr); 107820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 107920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 108020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 108120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & mask2) { 108220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 108320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask2, dc->reg_fcr); 108420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 108520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 108620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 108720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (*toggle == 1 && read_iir & mask2) { 108820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 108920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask2, dc->reg_fcr); 109020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 109120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 109220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 109320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & mask1) { 109420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 109520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask1, dc->reg_fcr); 109620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 109720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 109820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 109920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 110020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "port out of sync!, toggle:%d\n", 110120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle); 110220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 110320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 110420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 110520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 110620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 110720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 110820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Handle uplink data, this is currently for the modem port 110920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - ok 111020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - toggle field are out of sync 111120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 111220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int handle_data_ul(struct nozomi *dc, enum port_type port, u16 read_iir) 111320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 111420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 *toggle = &(dc->port[port].toggle_ul); 111520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 111620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (*toggle == 0 && read_iir & MDM_UL1) { 111720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 111820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 111920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 112020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL1, dc->reg_fcr); 112120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 112220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 112320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 112420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 112520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 112620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_UL2) { 112720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 112820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 112920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 113020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL2, dc->reg_fcr); 113120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 113220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 113320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 113420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 113520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 113620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 113720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (*toggle == 1 && read_iir & MDM_UL2) { 113820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 113920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 114020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 114120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL2, dc->reg_fcr); 114220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 114320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 114420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 114520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 114620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 114720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_UL1) { 114820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 114920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 115020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 115120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL1, dc->reg_fcr); 115220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 115320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 115420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 115520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 115620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 115720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 115820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(read_iir & MDM_UL, dc->reg_fcr); 115920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "port out of sync!\n"); 116020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 116120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 116220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 116320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 116420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 116520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic irqreturn_t interrupt_handler(int irq, void *dev_id) 116620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 116720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = dev_id; 116820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int a; 116920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 read_iir; 117020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 117120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc) 117220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return IRQ_NONE; 117320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 117420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock(&dc->spin_mutex); 117520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_iir = readw(dc->reg_iir); 117620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 117720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Card removed */ 117820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir == (u16)-1) 117920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto none; 118020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 118120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Just handle interrupt enabled in IER 118220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * (by masking with dc->last_ier) 118320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 118420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_iir &= dc->last_ier; 118520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 118620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir == 0) 118720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto none; 118820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 118920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 119020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG4("%s irq:0x%04X, prev:0x%04X", interrupt2str(read_iir), read_iir, 119120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier); 119220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 119320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & RESET) { 119420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!nozomi_read_config_table(dc))) { 119520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0x0; 119620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 119720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Could not read status from " 119820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "card, we should disable interface\n"); 119920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 120020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(RESET, dc->reg_fcr); 120120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 120220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* No more useful info if this was the reset interrupt. */ 120320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 120420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 120520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & CTRL_UL) { 120620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("CTRL_UL"); 120720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~CTRL_UL; 120820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 120920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_flow_control(dc)) { 121020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(CTRL_UL, dc->reg_fcr); 121120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | CTRL_UL; 121220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 121320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 121420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 121520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & CTRL_DL) { 121620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel receive_flow_control(dc); 121720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(CTRL_DL, dc->reg_fcr); 121820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 121920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_DL) { 122020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!handle_data_dl(dc, PORT_MDM, 122120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel &(dc->port[PORT_MDM].toggle_dl), read_iir, 122220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel MDM_DL1, MDM_DL2)) { 122320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "MDM_DL out of sync!\n"); 122420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 122520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 122620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 122720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_UL) { 122820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!handle_data_ul(dc, PORT_MDM, read_iir)) { 122920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "MDM_UL out of sync!\n"); 123020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 123120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 123220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 123320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & DIAG_DL) { 123420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!handle_data_dl(dc, PORT_DIAG, 123520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel &(dc->port[PORT_DIAG].toggle_dl), read_iir, 123620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DIAG_DL1, DIAG_DL2)) { 123720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "DIAG_DL out of sync!\n"); 123820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 123920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 124020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 124120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & DIAG_UL) { 124220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~DIAG_UL; 124320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 124420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(PORT_DIAG, dc)) { 124520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(DIAG_UL, dc->reg_fcr); 124620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | DIAG_UL; 124720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 124820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 124920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 125020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP1_DL) { 125120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(PORT_APP1, dc)) 125220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP1_DL, dc->reg_fcr); 125320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 125420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP1_UL) { 125520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~APP1_UL; 125620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 125720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(PORT_APP1, dc)) { 125820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP1_UL, dc->reg_fcr); 125920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | APP1_UL; 126020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 126120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 126220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 126320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP2_DL) { 126420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(PORT_APP2, dc)) 126520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP2_DL, dc->reg_fcr); 126620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 126720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP2_UL) { 126820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~APP2_UL; 126920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 127020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(PORT_APP2, dc)) { 127120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP2_UL, dc->reg_fcr); 127220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | APP2_UL; 127320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 127420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 127520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 127620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 127720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelexit_handler: 127820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock(&dc->spin_mutex); 127920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (a = 0; a < NOZOMI_MAX_PORTS; a++) 128020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (test_and_clear_bit(a, &dc->flip)) 128120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_flip_buffer_push(dc->port[a].tty); 128220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return IRQ_HANDLED; 128320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelnone: 128420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock(&dc->spin_mutex); 128520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return IRQ_NONE; 128620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 128720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 128820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void nozomi_get_card_type(struct nozomi *dc) 128920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 129020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 129120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size = 0; 129220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 129320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < 6; i++) 129420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel size += pci_resource_len(dc->pdev, i); 129520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 129620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Assume card type F32_8 if no match */ 129720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->card_type = size == 2048 ? F32_2 : F32_8; 129820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 129920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_info(&dc->pdev->dev, "Card type is: %d\n", dc->card_type); 130020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 130120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 130220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void nozomi_setup_private_data(struct nozomi *dc) 130320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 130420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *offset = dc->base_addr + dc->card_type / 2; 130520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int i; 130620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 130720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->reg_fcr = (void __iomem *)(offset + R_FCR); 130820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->reg_iir = (void __iomem *)(offset + R_IIR); 130920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->reg_ier = (void __iomem *)(offset + R_IER); 131020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0; 131120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->flip = 0; 131220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 131320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].token_dl = MDM_DL; 131420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].token_dl = DIAG_DL; 131520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].token_dl = APP1_DL; 131620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].token_dl = APP2_DL; 131720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 131820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < MAX_PORT; i++) 131920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel init_waitqueue_head(&dc->port[i].tty_wait); 132020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 132120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 132220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic ssize_t card_type_show(struct device *dev, struct device_attribute *attr, 132320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char *buf) 132420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 132571e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); 132620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 132720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return sprintf(buf, "%d\n", dc->card_type); 132820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 1329e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidelstatic DEVICE_ATTR(card_type, S_IRUGO, card_type_show, NULL); 133020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 133120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr, 133220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char *buf) 133320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 133471e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); 133520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 133620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return sprintf(buf, "%u\n", dc->open_ttys); 133720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 1338e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidelstatic DEVICE_ATTR(open_ttys, S_IRUGO, open_ttys_show, NULL); 133920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 134020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void make_sysfs_files(struct nozomi *dc) 134120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 134220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (device_create_file(&dc->pdev->dev, &dev_attr_card_type)) 134320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 134420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "Could not create sysfs file for card_type\n"); 134520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (device_create_file(&dc->pdev->dev, &dev_attr_open_ttys)) 134620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 134720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "Could not create sysfs file for open_ttys\n"); 134820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 134920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 135020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void remove_sysfs_files(struct nozomi *dc) 135120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 135220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel device_remove_file(&dc->pdev->dev, &dev_attr_card_type); 135320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel device_remove_file(&dc->pdev->dev, &dev_attr_open_ttys); 135420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 135520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 135620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Allocate memory for one device */ 135720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int __devinit nozomi_card_init(struct pci_dev *pdev, 135820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel const struct pci_device_id *ent) 135920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 136020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel resource_size_t start; 136120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ret; 136220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = NULL; 136320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ndev_idx; 136420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 136520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 136620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_dbg(&pdev->dev, "Init, new card found\n"); 136720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 136820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (ndev_idx = 0; ndev_idx < ARRAY_SIZE(ndevs); ndev_idx++) 136920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!ndevs[ndev_idx]) 137020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 137120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 137220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ndev_idx >= ARRAY_SIZE(ndevs)) { 137320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "no free tty range for this card left\n"); 137420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -EIO; 137520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err; 137620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 137720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 137820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc = kzalloc(sizeof(struct nozomi), GFP_KERNEL); 137920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!dc)) { 138020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Could not allocate memory\n"); 138120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -ENOMEM; 138220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_free; 138320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 138420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 138520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->pdev = pdev; 138620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 138720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = pci_enable_device(dc->pdev); 138820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 138920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Failed to enable PCI Device\n"); 139020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_free; 139120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 139220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 139320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = pci_request_regions(dc->pdev, NOZOMI_NAME); 139420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 139520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "I/O address 0x%04x already in use\n", 139620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (int) /* nozomi_private.io_addr */ 0); 139720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_disable_device; 139820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 139920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1400661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel start = pci_resource_start(dc->pdev, 0); 1401661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel if (start == 0) { 1402661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dev_err(&pdev->dev, "No I/O address for card detected\n"); 1403661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel ret = -ENODEV; 1404661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel goto err_rel_regs; 1405661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel } 1406661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1407661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel /* Find out what card type it is */ 1408661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel nozomi_get_card_type(dc); 1409661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 141024cb233520f01971d6d873cb52c64bbbb0665ac0Alan Cox dc->base_addr = ioremap_nocache(start, dc->card_type); 141120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc->base_addr) { 141220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Unable to map card MMIO\n"); 141320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -ENODEV; 141420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_rel_regs; 141520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 141620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 141720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->send_buf = kmalloc(SEND_BUF_MAX, GFP_KERNEL); 141820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc->send_buf) { 141920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Could not allocate send buffer?\n"); 142020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -ENOMEM; 142120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_free_sbuf; 142220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 142320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 142420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_init(&dc->spin_mutex); 142520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 142620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel nozomi_setup_private_data(dc); 142720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 142820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Disable all interrupts */ 142920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0; 143020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 143120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 143220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = request_irq(pdev->irq, &interrupt_handler, IRQF_SHARED, 143320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel NOZOMI_NAME, dc); 143420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(ret)) { 143520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq); 143620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_free_sbuf; 143720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 143820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 143920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("base_addr: %p", dc->base_addr); 144020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 144120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel make_sysfs_files(dc); 144220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 144320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->index_start = ndev_idx * MAX_PORT; 144420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ndevs[ndev_idx] = dc; 144520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1446661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel pci_set_drvdata(pdev, dc); 1447661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1448661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel /* Enable RESET interrupt */ 1449661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->last_ier = RESET; 1450661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel iowrite16(dc->last_ier, dc->reg_ier); 1451661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1452661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->state = NOZOMI_STATE_ENABLED; 1453661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 145420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < MAX_PORT; i++) { 145520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel mutex_init(&dc->port[i].tty_sem); 145620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[i].tty_open_count = 0; 145720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[i].tty = NULL; 145820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_register_device(ntty_driver, dc->index_start + i, 145920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel &pdev->dev); 146020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 146120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 146220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 146320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 146420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_free_sbuf: 146520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc->send_buf); 146620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel iounmap(dc->base_addr); 146720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_rel_regs: 146820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_release_regions(pdev); 146920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_disable_device: 147020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_disable_device(pdev); 147120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_free: 147220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc); 147320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr: 147420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ret; 147520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 147620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 147720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void __devexit tty_exit(struct nozomi *dc) 147820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 147920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int i; 148020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 148120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1(" "); 148220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 148320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel flush_scheduled_work(); 148420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 148520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < MAX_PORT; ++i) 148620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (dc->port[i].tty && \ 148720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel list_empty(&dc->port[i].tty->hangup_work.entry)) 148820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_hangup(dc->port[i].tty); 148920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 149020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel while (dc->open_ttys) 149120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel msleep(1); 149220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 149320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i) 149420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_unregister_device(ntty_driver, i); 149520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 149620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 149720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Deallocate memory for one device */ 149820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void __devexit nozomi_card_exit(struct pci_dev *pdev) 149920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 150020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 150120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_ul ctrl; 150220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = pci_get_drvdata(pdev); 150320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 150420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Disable all interrupts */ 150520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0; 150620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 150720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 150820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_exit(dc); 150920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 151020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Send 0x0001, command card to resend the reset token. */ 151120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* This is to get the reset when the module is reloaded. */ 151220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.port = 0x00; 151320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.reserved = 0; 151420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.RTS = 0; 151520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.DTR = 1; 151620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("sending flow control 0x%04X", *((u16 *)&ctrl)); 151720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 151820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Setup dc->reg addresses to we can use defines here */ 151920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_CTRL].ul_addr[0], (u32 *)&ctrl, 2); 152020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(CTRL_UL, dc->reg_fcr); /* push the token to the card. */ 152120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 152220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel remove_sysfs_files(dc); 152320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 152420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel free_irq(pdev->irq, dc); 152520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 152620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < MAX_PORT; i++) 152720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (dc->port[i].fifo_ul) 152820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfifo_free(dc->port[i].fifo_ul); 152920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 153020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc->send_buf); 153120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 153220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel iounmap(dc->base_addr); 153320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 153420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_release_regions(pdev); 153520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 153620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_disable_device(pdev); 153720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 153820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ndevs[dc->index_start / MAX_PORT] = NULL; 153920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 154020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc); 154120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 154220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 154320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void set_rts(const struct tty_struct *tty, int rts) 154420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 154520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = get_port_by_tty(tty); 154620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 154720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->ctrl_ul.RTS = rts; 154820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->update_flow_control = 1; 154920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); 155020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 155120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 155220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void set_dtr(const struct tty_struct *tty, int dtr) 155320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 155420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = get_port_by_tty(tty); 155520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 155620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("SETTING DTR index: %d, dtr: %d", tty->index, dtr); 155720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 155820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->ctrl_ul.DTR = dtr; 155920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->update_flow_control = 1; 156020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); 156120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 156220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 156420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * ---------------------------------------------------------------------------- 156520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * TTY code 156620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * ---------------------------------------------------------------------------- 156720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 156820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Called when the userspace process opens the tty, /dev/noz*. */ 157020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_open(struct tty_struct *tty, struct file *file) 157120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 157220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = get_port_by_tty(tty); 157320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 157420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 157520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1576661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel if (!port || !dc || dc->state != NOZOMI_STATE_READY) 157720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return -ENODEV; 157820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 157920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (mutex_lock_interruptible(&port->tty_sem)) 158020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return -ERESTARTSYS; 158120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 158220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->tty_open_count++; 158320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->open_ttys++; 158420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 158520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Enable interrupt downlink for channel */ 158620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port->tty_open_count == 1) { 158720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty->low_latency = 1; 158820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty->driver_data = port; 158920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->tty = tty; 159020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("open: %d", port->token_dl); 159120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 159220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | port->token_dl; 159320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 159420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 159520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 159620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 159720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel mutex_unlock(&port->tty_sem); 159820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 159920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 160020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 160120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1602716da631ae91fc5e9f8d5815f8ef5fbfed862b80Alan Cox/* Called when the userspace process close the tty, /dev/noz*. Also 1603716da631ae91fc5e9f8d5815f8ef5fbfed862b80Alan Cox called immediately if ntty_open fails in which case tty->driver_data 1604716da631ae91fc5e9f8d5815f8ef5fbfed862b80Alan Cox will be NULL an we exit by the first return */ 1605716da631ae91fc5e9f8d5815f8ef5fbfed862b80Alan Cox 160620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void ntty_close(struct tty_struct *tty, struct file *file) 160720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 160820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 160920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 161020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 161120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 161220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc || !port) 161320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return; 161420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 161520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (mutex_lock_interruptible(&port->tty_sem)) 161620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return; 161720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 161820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!port->tty_open_count) 161920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit; 162020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 162120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->open_ttys--; 162220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->tty_open_count--; 162320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 162420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port->tty_open_count == 0) { 162520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("close: %d", port->token_dl); 162620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 162720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~(port->token_dl); 162820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 162920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 163020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 163120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 163220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelexit: 163320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel mutex_unlock(&port->tty_sem); 163420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 163520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 163620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 163720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * called when the userspace process writes to the tty (/dev/noz*). 163820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Data is inserted into a fifo, which is then read and transfered to the modem. 163920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 164020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_write(struct tty_struct *tty, const unsigned char *buffer, 164120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int count) 164220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 164320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int rval = -EINVAL; 164420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 164520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 164620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 164720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 164820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* DBG1( "WRITEx: %d, index = %d", count, index); */ 164920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 165020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc || !port) 165120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return -ENODEV; 165220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 165320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!mutex_trylock(&port->tty_sem))) { 165420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 165520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * must test lock as tty layer wraps calls 165620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * to this function with BKL 165720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 165820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Would have deadlocked - " 165920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "return EAGAIN\n"); 166020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return -EAGAIN; 166120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 166220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 166320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!port->tty_open_count)) { 166420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1(" "); 166520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit; 166620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 166720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 166820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel rval = __kfifo_put(port->fifo_ul, (unsigned char *)buffer, count); 166920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 167020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* notify card */ 167120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(dc == NULL)) { 167220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("No device context?"); 167320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit; 167420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 167520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 167620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 167720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* CTS is only valid on the modem channel */ 167820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port == &(dc->port[PORT_MDM])) { 167920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port->ctrl_dl.CTS) { 168020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG4("Enable interrupt"); 168120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(tty->index % MAX_PORT, dc); 168220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 168320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 168420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "CTS not active on modem port?\n"); 168520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 168620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 168720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(tty->index % MAX_PORT, dc); 168820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 168920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 169020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 169120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelexit: 169220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel mutex_unlock(&port->tty_sem); 169320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return rval; 169420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 169520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 169620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 169720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Calculate how much is left in device 169820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * This method is called by the upper tty layer. 169920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * #according to sources N_TTY.c it expects a value >= 0 and 170020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * does not check for negative values. 170120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 170220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_write_room(struct tty_struct *tty) 170320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 170420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 170520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int room = 0; 170671e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct nozomi *dc = get_dc_by_tty(tty); 170720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 170820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc || !port) 170920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 171020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!mutex_trylock(&port->tty_sem)) 171120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 171220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 171320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!port->tty_open_count) 171420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit; 171520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 171620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel room = port->fifo_ul->size - __kfifo_len(port->fifo_ul); 171720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 171820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelexit: 171920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel mutex_unlock(&port->tty_sem); 172020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return room; 172120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 172220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 172320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Gets io control parameters */ 172420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_tiocmget(struct tty_struct *tty, struct file *file) 172520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 172671e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct port *port = tty->driver_data; 172771e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct ctrl_dl *ctrl_dl = &port->ctrl_dl; 172871e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct ctrl_ul *ctrl_ul = &port->ctrl_ul; 172920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1730978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox /* Note: these could change under us but it is not clear this 1731978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox matters if so */ 173220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return (ctrl_ul->RTS ? TIOCM_RTS : 0) | 173320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_ul->DTR ? TIOCM_DTR : 0) | 173420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->DCD ? TIOCM_CAR : 0) | 173520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->RI ? TIOCM_RNG : 0) | 173620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->DSR ? TIOCM_DSR : 0) | 173720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->CTS ? TIOCM_CTS : 0); 173820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 173920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 174020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Sets io controls parameters */ 174120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_tiocmset(struct tty_struct *tty, struct file *file, 174220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int set, unsigned int clear) 174320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 1744661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 1745661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel unsigned long flags; 1746661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1747661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 174820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (set & TIOCM_RTS) 174920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 1); 175020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel else if (clear & TIOCM_RTS) 175120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 0); 175220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 175320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (set & TIOCM_DTR) 175420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_dtr(tty, 1); 175520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel else if (clear & TIOCM_DTR) 175620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_dtr(tty, 0); 1757661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 175820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 175920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 176020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 176120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 176220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_cflags_changed(struct port *port, unsigned long flags, 176320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct async_icount *cprev) 176420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 176518bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const struct async_icount cnow = port->tty_icount; 176620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ret; 176720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 176820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = ((flags & TIOCM_RNG) && (cnow.rng != cprev->rng)) || 176920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ((flags & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || 177020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ((flags & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || 177120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ((flags & TIOCM_CTS) && (cnow.cts != cprev->cts)); 177220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 177320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *cprev = cnow; 177420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 177520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ret; 177620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 177720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 177820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_ioctl_tiocgicount(struct port *port, void __user *argp) 177920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 178018bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const struct async_icount cnow = port->tty_icount; 178120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct serial_icounter_struct icount; 178220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 178320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel icount.cts = cnow.cts; 178420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel icount.dsr = cnow.dsr; 178520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel icount.rng = cnow.rng; 178620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel icount.dcd = cnow.dcd; 178720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel icount.rx = cnow.rx; 178820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel icount.tx = cnow.tx; 178920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel icount.frame = cnow.frame; 179020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel icount.overrun = cnow.overrun; 179120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel icount.parity = cnow.parity; 179220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel icount.brk = cnow.brk; 179320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel icount.buf_overrun = cnow.buf_overrun; 179420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1795661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel return copy_to_user(argp, &icount, sizeof(icount)) ? -EFAULT : 0; 179620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 179720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 179820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_ioctl(struct tty_struct *tty, struct file *file, 179920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int cmd, unsigned long arg) 180020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 180120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 180220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __user *argp = (void __user *)arg; 180320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int rval = -ENOIOCTLCMD; 180420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 180520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("******** IOCTL, cmd: %d", cmd); 180620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 180720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (cmd) { 180820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case TIOCMIWAIT: { 180920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct async_icount cprev = port->tty_icount; 181020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 181120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel rval = wait_event_interruptible(port->tty_wait, 181220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_cflags_changed(port, arg, &cprev)); 181320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 181420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } case TIOCGICOUNT: 181520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel rval = ntty_ioctl_tiocgicount(port, argp); 181620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 181720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel default: 181820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("ERR: 0x%08X, %d", cmd, cmd); 181920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 182020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel }; 182120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 182220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return rval; 182320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 182420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 182520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 182620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Called by the upper tty layer when tty buffers are ready 182720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * to receive data again after a call to throttle. 182820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 182920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void ntty_unthrottle(struct tty_struct *tty) 183020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 183120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 183220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 183320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 183420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("UNTHROTTLE"); 183520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 183620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_dl(tty->index % MAX_PORT, dc); 183720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 1); 183820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 183920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 184020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 184120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 184220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 184320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Called by the upper tty layer when the tty buffers are almost full. 184420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * The driver should stop send more data. 184520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 184620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void ntty_throttle(struct tty_struct *tty) 184720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 184820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 184920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 185020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 185120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("THROTTLE"); 185220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 185320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 0); 185420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 185520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 185620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 185720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Returns number of chars in buffer, called by tty layer */ 185820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic s32 ntty_chars_in_buffer(struct tty_struct *tty) 185920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 186020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 186120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 186220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel s32 rval; 186320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 186420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!dc || !port)) { 186520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel rval = -ENODEV; 186620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_in_buffer; 186720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 186820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 186920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!port->tty_open_count)) { 187020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "No tty open?\n"); 187120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel rval = -ENODEV; 187220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_in_buffer; 187320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 187420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 187520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel rval = __kfifo_len(port->fifo_ul); 187620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 187720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelexit_in_buffer: 187820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return rval; 187920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 188020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 188118bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidelstatic const struct tty_operations tty_ops = { 188220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .ioctl = ntty_ioctl, 188320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .open = ntty_open, 188420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .close = ntty_close, 188520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .write = ntty_write, 188620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .write_room = ntty_write_room, 188720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .unthrottle = ntty_unthrottle, 188820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .throttle = ntty_throttle, 188920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .chars_in_buffer = ntty_chars_in_buffer, 189020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .tiocmget = ntty_tiocmget, 189120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .tiocmset = ntty_tiocmset, 189220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 189320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 189420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Module initialization */ 189520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic struct pci_driver nozomi_driver = { 189620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .name = NOZOMI_NAME, 189720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .id_table = nozomi_pci_tbl, 189820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .probe = nozomi_card_init, 189920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .remove = __devexit_p(nozomi_card_exit), 190020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 190120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 190220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic __init int nozomi_init(void) 190320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 190420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ret; 190520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 190620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_INFO "Initializing %s\n", VERSION_STRING); 190720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 190820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver = alloc_tty_driver(NTTY_TTY_MAXMINORS); 190920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!ntty_driver) 191020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return -ENOMEM; 191120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 191220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->owner = THIS_MODULE; 191320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->driver_name = NOZOMI_NAME_TTY; 191420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->name = "noz"; 191520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->major = 0; 191620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->type = TTY_DRIVER_TYPE_SERIAL; 191720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->subtype = SERIAL_TYPE_NORMAL; 191820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 191920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios = tty_std_termios; 192020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | \ 192120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel HUPCL | CLOCAL; 192220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios.c_ispeed = 115200; 192320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios.c_ospeed = 115200; 192420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_set_operations(ntty_driver, &tty_ops); 192520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 192620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = tty_register_driver(ntty_driver); 192720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 192820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_ERR "Nozomi: failed to register ntty driver\n"); 192920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto free_tty; 193020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 193120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 193220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = pci_register_driver(&nozomi_driver); 193320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 193420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_ERR "Nozomi: can't register pci driver\n"); 193520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto unr_tty; 193620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 193720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 193820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 193920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelunr_tty: 194020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_unregister_driver(ntty_driver); 194120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelfree_tty: 194220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel put_tty_driver(ntty_driver); 194320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ret; 194420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 194520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 194620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic __exit void nozomi_exit(void) 194720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 194820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_INFO "Unloading %s\n", DRIVER_DESC); 194920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_unregister_driver(&nozomi_driver); 195020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_unregister_driver(ntty_driver); 195120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel put_tty_driver(ntty_driver); 195220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 195320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 195420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelmodule_init(nozomi_init); 195520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelmodule_exit(nozomi_exit); 195620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 195720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelmodule_param(debug, int, S_IRUGO | S_IWUSR); 195820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 195920fd1e3bea554620d489f3542496639c1babe0b3Frank SeidelMODULE_LICENSE("Dual BSD/GPL"); 196020fd1e3bea554620d489f3542496639c1babe0b3Frank SeidelMODULE_DESCRIPTION(DRIVER_DESC); 1961