nozomi.c revision 2cae8de7b0464cc4c246517fca10f04593f46a3b
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> 51d43c36dc6b357fa1806800f18aa30123c747a6d1Alexey Dobriyan#include <linux/sched.h> 5220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/serial.h> 5320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/interrupt.h> 5420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/kmod.h> 5520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/init.h> 5620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/kfifo.h> 5720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/uaccess.h> 585a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 5920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <asm/byteorder.h> 6020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 6120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/delay.h> 6220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 6320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 642cae8de7b0464cc4c246517fca10f04593f46a3bMichal Marek#define VERSION_STRING DRIVER_DESC " 2.1d" 6520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 6620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Macros definitions */ 6720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 6820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Default debug printout level */ 6920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_DEBUG_LEVEL 0x00 7020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 7120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define P_BUF_SIZE 128 7220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NFO(_err_flag_, args...) \ 7320fd1e3bea554620d489f3542496639c1babe0b3Frank Seideldo { \ 7420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char tmp[P_BUF_SIZE]; \ 7520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel snprintf(tmp, sizeof(tmp), ##args); \ 7620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(_err_flag_ "[%d] %s(): %s\n", __LINE__, \ 77bf9d89295233ae2ba7b312c78ee5657307b09f4cHarvey Harrison __func__, tmp); \ 7820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} while (0) 7920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 8020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG1(args...) D_(0x01, ##args) 8120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG2(args...) D_(0x02, ##args) 8220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG3(args...) D_(0x04, ##args) 8320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG4(args...) D_(0x08, ##args) 8420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG5(args...) D_(0x10, ##args) 8520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG6(args...) D_(0x20, ##args) 8620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG7(args...) D_(0x40, ##args) 8720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG8(args...) D_(0x80, ##args) 8820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 8920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef DEBUG 9020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Do we need this settable at runtime? */ 9120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int debug = NOZOMI_DEBUG_LEVEL; 9220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 93e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel#define D(lvl, args...) do \ 94e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \ 95e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel while (0) 9620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define D_(lvl, args...) D(lvl, ##args) 9720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 9820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* These printouts are always printed */ 9920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 10020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#else 10120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int debug; 10220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define D_(lvl, args...) 10320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 10420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 10520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* TODO: rewrite to optimize macros... */ 10620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 10720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define TMP_BUF_MAX 256 10820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 10920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DUMP(buf__,len__) \ 11020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel do { \ 11120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char tbuf[TMP_BUF_MAX] = {0};\ 11220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (len__ > 1) {\ 11320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel snprintf(tbuf, len__ > TMP_BUF_MAX ? TMP_BUF_MAX : len__, "%s", buf__);\ 11420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (tbuf[len__-2] == '\r') {\ 11520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tbuf[len__-2] = 'r';\ 11620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } \ 11720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("SENDING: '%s' (%d+n)", tbuf, len__);\ 11820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else {\ 11920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("SENDING: '%s' (%d)", tbuf, len__);\ 12020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } \ 12120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} while (0) 12220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 12320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Defines */ 12420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_NAME "nozomi" 12520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_NAME_TTY "nozomi_tty" 12620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DRIVER_DESC "Nozomi driver" 12720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 12820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NTTY_TTY_MAXMINORS 256 12920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NTTY_FIFO_BUFFER_SIZE 8192 13020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Must be power of 2 */ 13220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define FIFO_BUFFER_SIZE_UL 8192 13320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Size of tmp send buffer to card */ 13520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define SEND_BUF_MAX 1024 13620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define RECEIVE_BUF_MAX 4 13720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define R_IIR 0x0000 /* Interrupt Identity Register */ 14020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define R_FCR 0x0000 /* Flow Control Register */ 14120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define R_IER 0x0004 /* Interrupt Enable Register */ 14220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CONFIG_MAGIC 0xEFEFFEFE 14420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define TOGGLE_VALID 0x0000 14520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Definition of interrupt tokens */ 14720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_DL1 0x0001 14820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_UL1 0x0002 14920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_DL2 0x0004 15020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_UL2 0x0008 15120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_DL1 0x0010 15220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_DL2 0x0020 15320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_UL 0x0040 15420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP1_DL 0x0080 15520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP1_UL 0x0100 15620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP2_DL 0x0200 15720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP2_UL 0x0400 15820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DL 0x0800 15920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_UL 0x1000 16020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define RESET 0x8000 16120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 16220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_DL (MDM_DL1 | MDM_DL2) 16320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_UL (MDM_UL1 | MDM_UL2) 16420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_DL (DIAG_DL1 | DIAG_DL2) 16520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 16620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* modem signal definition */ 16720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DSR 0x0001 16820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DCD 0x0002 16920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_RI 0x0004 17020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_CTS 0x0008 17120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 17220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DTR 0x0001 17320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_RTS 0x0002 17420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 17520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MAX_PORT 4 17620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_MAX_PORTS 5 17720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_MAX_CARDS (NTTY_TTY_MAXMINORS / MAX_PORT) 17820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 17920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Type definitions */ 18020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 18120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 18220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * There are two types of nozomi cards, 18320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * one with 2048 memory and with 8192 memory 18420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 18520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum card_type { 18620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel F32_2 = 2048, /* 512 bytes downlink + uplink * 2 -> 2048 */ 18720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel F32_8 = 8192, /* 3072 bytes downl. + 1024 bytes uplink * 2 -> 8192 */ 18820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 18920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 190661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel/* Initialization states a card can be in */ 191661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidelenum card_state { 192661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_UKNOWN = 0, 193661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_ENABLED = 1, /* pci device enabled */ 194661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_ALLOCATED = 2, /* config setup done */ 195661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_READY = 3, /* flowcontrols received */ 196661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel}; 197661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 19820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Two different toggle channels exist */ 19920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum channel_type { 20020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CH_A = 0, 20120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CH_B = 1, 20220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 20320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 20420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Port definition for the card regarding flow control */ 20520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum ctrl_port_type { 20620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_CMD = 0, 20720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_MDM = 1, 20820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_DIAG = 2, 20920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_APP1 = 3, 21020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_APP2 = 4, 21120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_ERROR = -1, 21220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 21320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 21420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Ports that the nozomi has */ 21520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum port_type { 21620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_MDM = 0, 21720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_DIAG = 1, 21820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_APP1 = 2, 21920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_APP2 = 3, 22020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_CTRL = 4, 22120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_ERROR = -1, 22220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 22320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 22420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef __BIG_ENDIAN 22520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Big endian */ 22620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 22720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct toggles { 228e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int enabled:5; /* 22920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Toggle fields are valid if enabled is 0, 23020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * else A-channels must always be used. 23120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 232e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int diag_dl:1; 233e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_dl:1; 234e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_ul:1; 23520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 23620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 23720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Configuration table to read at startup of card */ 23820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Is for now only needed during initialization phase */ 23920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct config_table { 24020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 signature; 24120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 product_information; 24220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 version; 24320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad3[3]; 24420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct toggles toggle; 24520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad1[4]; 24620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len1; /* 24720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * If this is 64, it can hold 24820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 60 bytes + 4 that is length field 24920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 25020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_start; 25120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 25220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len1; 25320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len2; /* 25420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * If this is 64, it can hold 25520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 60 bytes + 4 that is length field 25620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 25720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app1_len; 25820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 25920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len2; 26020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_ctrl_len; 26120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app2_len; 26220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad2[16]; 26320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len1; 26420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_start; 26520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_diag_len; 26620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len2; 26720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app1_len; 26820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app2_len; 26920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_ctrl_len; 27020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 27120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 27220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control downlink flags */ 27320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_dl { 27420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 275e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserved:4; 276e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int CTS:1; 277e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RI:1; 278e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DCD:1; 279e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DSR:1; 28020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 28120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 28220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control uplink flags */ 28320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_ul { 28420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 285e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserved:6; 286e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RTS:1; 287e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DTR:1; 28820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 28920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 29020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#else 29120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Little endian */ 29220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 29320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This represents the toggle information */ 29420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct toggles { 295e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_ul:1; 296e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_dl:1; 297e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int diag_dl:1; 298e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int enabled:5; /* 29920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Toggle fields are valid if enabled is 0, 30020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * else A-channels must always be used. 30120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 30220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 30320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 30420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Configuration table to read at startup of card */ 30520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct config_table { 30620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 signature; 30720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 version; 30820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 product_information; 30920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct toggles toggle; 31020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad1[7]; 31120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_start; 31220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len1; /* 31320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * If this is 64, it can hold 31420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 60 bytes + 4 that is length field 31520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 31620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len2; 31720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len1; 31820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len2; 31920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app1_len; 32020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app2_len; 32120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_ctrl_len; 32220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad2[16]; 32320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_start; 32420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len2; 32520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len1; 32620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_diag_len; 32720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app1_len; 32820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app2_len; 32920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_ctrl_len; 33020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 33120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 33220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control downlink flags */ 33320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_dl { 334e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DSR:1; 335e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DCD:1; 336e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RI:1; 337e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int CTS:1; 338e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserverd:4; 33920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 34020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 34120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 34220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control uplink flags */ 34320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_ul { 344e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DTR:1; 345e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RTS:1; 346e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserved:6; 34720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 34820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 34920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 35020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 35120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This holds all information that is needed regarding a port */ 35220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct port { 35333dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_port port; 35420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 update_flow_control; 35520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_ul ctrl_ul; 35620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_dl ctrl_dl; 35745465487897a1c6d508b14b904dc5777f7ec7e04Stefani Seibold struct kfifo fifo_ul; 35820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *dl_addr[2]; 35920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 dl_size[2]; 36020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 toggle_dl; 36120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *ul_addr[2]; 36220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 ul_size[2]; 36320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 toggle_ul; 36420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 token_dl; 36520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 36620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* mutex to ensure one access patch to this port */ 36720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct mutex tty_sem; 36820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel wait_queue_head_t tty_wait; 36920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct async_icount tty_icount; 370266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox 371266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct nozomi *dc; 37220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 37320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 37420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Private data one for each card in the system */ 37520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct nozomi { 37620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *base_addr; 37720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flip; 37820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 37920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Pointers to registers */ 38020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *reg_iir; 38120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *reg_fcr; 38220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *reg_ier; 38320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 38420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 last_ier; 38520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enum card_type card_type; 38620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct config_table config_table; /* Configuration table */ 38720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct pci_dev *pdev; 38820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port port[NOZOMI_MAX_PORTS]; 38920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 *send_buf; 39020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 39120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spinlock_t spin_mutex; /* secures access to registers and tty */ 39220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 39320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int index_start; 394661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel enum card_state state; 39520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 open_ttys; 39620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 39720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 39820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This is a data packet that is read or written to/from card */ 39920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct buffer { 40020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size; /* size is the length of the data buffer */ 40120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 *data; 40220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 40320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 40420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Global variables */ 40518bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidelstatic const struct pci_device_id nozomi_pci_tbl[] __devinitconst = { 406b2a3dbc3ed401828c4de0f08d08d96d0f5ea5b0bAlan Cox {PCI_DEVICE(0x1931, 0x000c)}, /* Nozomi HSDPA */ 40720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel {}, 40820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 40920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 41020fd1e3bea554620d489f3542496639c1babe0b3Frank SeidelMODULE_DEVICE_TABLE(pci, nozomi_pci_tbl); 41120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 41220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic struct nozomi *ndevs[NOZOMI_MAX_CARDS]; 41320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic struct tty_driver *ntty_driver; 41420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 415266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic const struct tty_port_operations noz_tty_port_ops; 416266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox 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 memset(&dc->port[i].ctrl_dl, 0, sizeof(struct ctrl_dl)); 68920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel memset(&dc->port[i].ctrl_ul, 0, sizeof(struct ctrl_ul)); 69020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 69120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 69220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Enable control channel */ 69320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | CTRL_DL; 69420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 69520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 696661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->state = NOZOMI_STATE_ALLOCATED; 69720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_info(&dc->pdev->dev, "Initialization OK!\n"); 69820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 69920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 70020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 70120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if ((dc->config_table.version > 0) 70220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel && (dc->config_table.toggle.enabled != TOGGLE_VALID)) { 70320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 offset = 0; 70420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("First phase: pushing upload buffers, clearing download"); 70520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 70620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_info(&dc->pdev->dev, "Version of card: %d\n", 70720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.version); 70820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 70920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Here we should disable all I/O over F32. */ 71020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel setup_memory(dc); 71120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 71220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 71320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * We should send ALL channel pair tokens back along 71420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * with reset token 71520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 71620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 71720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* push upload modem buffers */ 71820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_MDM].ul_addr[CH_A], 71920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (u32 *) &offset, 4); 72020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_MDM].ul_addr[CH_B], 72120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (u32 *) &offset, 4); 72220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 72320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL | DIAG_DL | MDM_DL, dc->reg_fcr); 72420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 72520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("First phase done"); 72620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 72720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 72820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 72920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 73020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 73120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Enable uplink interrupts */ 73220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void enable_transmit_ul(enum port_type port, struct nozomi *dc) 73320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 73471e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL}; 73520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 73620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 73720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier |= mask[port]; 73820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 73920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 74020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 74120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 74220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 74320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 74420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Disable uplink interrupts */ 74520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void disable_transmit_ul(enum port_type port, struct nozomi *dc) 74620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 74771e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = 74871e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL}; 74920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 75020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 75120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= mask[port]; 75220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 75320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 75420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 75520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 75620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 75720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 75820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Enable downlink interrupts */ 75920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void enable_transmit_dl(enum port_type port, struct nozomi *dc) 76020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 76171e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL}; 76220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 76320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 76420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier |= mask[port]; 76520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 76620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 76720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 76820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 76920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 77020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 77120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Disable downlink interrupts */ 77220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void disable_transmit_dl(enum port_type port, struct nozomi *dc) 77320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 77471e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = 77571e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL}; 77620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 77720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 77820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= mask[port]; 77920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 78020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 78120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 78220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 78320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 78420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 78520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 78620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - send buffer to card and ack. 78720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - don't ack, don't send buffer to card. 78820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 78933dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Coxstatic int send_data(enum port_type index, struct nozomi *dc) 79020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 79120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size = 0; 79233dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct port *port = &dc->port[index]; 79318bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const u8 toggle = port->toggle_ul; 79420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *addr = port->ul_addr[toggle]; 79518bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const u32 ul_size = port->ul_size[toggle]; 79633dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_struct *tty = tty_port_tty_get(&port->port); 79720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 79820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Get data from tty and place in buf for now */ 7997acd72eb85f1c7a15e8b5eb554994949241737f1Stefani Seibold size = kfifo_out(&port->fifo_ul, dc->send_buf, 80020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ul_size < SEND_BUF_MAX ? ul_size : SEND_BUF_MAX); 80120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 80220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (size == 0) { 80320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG4("No more data to send, disable link:"); 80433dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 80520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 80620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 80720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 80820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* DUMP(buf, size); */ 80920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 81020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Write length + data */ 81120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(addr, (u32 *) &size, 4); 81220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(addr + 4, (u32 *) dc->send_buf, size); 81320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 81420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (tty) 81520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_wakeup(tty); 81620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 81733dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 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]; 82933dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_struct *tty = tty_port_tty_get(&port->port); 8309237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby int i, ret; 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); 8469237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby ret = 0; 8479237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby goto put; 84820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 84920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 85020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(size == 0)) { 85120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "size == 0?\n"); 8529237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby ret = 1; 8539237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby goto put; 85420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 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); 8739237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby ret = 1; 8749237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slabyput: 87533dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 8769237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby return ret; 87720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 87820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 87920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Debug for interrupts */ 88020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef DEBUG 88120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic char *interrupt2str(u16 interrupt) 88220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 88320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel static char buf[TMP_BUF_MAX]; 88420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char *p = buf; 88520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 88620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_DL1 ? p += snprintf(p, TMP_BUF_MAX, "MDM_DL1 ") : NULL; 88720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 88820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "MDM_DL2 ") : NULL; 88920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 89020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_UL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "MDM_UL1 ") : NULL; 89220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_UL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "MDM_UL2 ") : NULL; 89420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 89520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & DIAG_DL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "DIAG_DL1 ") : NULL; 89720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & DIAG_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "DIAG_DL2 ") : NULL; 89920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 90020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & DIAG_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "DIAG_UL ") : NULL; 90220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 90320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP1_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP1_DL ") : NULL; 90520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP2_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP2_DL ") : NULL; 90720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 90820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP1_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP1_UL ") : NULL; 91020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP2_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 91120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP2_UL ") : NULL; 91220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 91320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & CTRL_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 91420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "CTRL_DL ") : NULL; 91520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & CTRL_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 91620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "CTRL_UL ") : NULL; 91720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 91820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & RESET ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 91920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "RESET ") : NULL; 92020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 92120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return buf; 92220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 92320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 92420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 92520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 92620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Receive flow control 92720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - If ok, else 0 92820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 92920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int receive_flow_control(struct nozomi *dc) 93020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 93120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enum port_type port = PORT_MDM; 93220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_dl ctrl_dl; 93320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_dl old_ctrl; 93420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 enable_ier = 0; 93520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 93620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_mem32((u32 *) &ctrl_dl, dc->port[PORT_CTRL].dl_addr[CH_A], 2); 93720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 93820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (ctrl_dl.port) { 93920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_CMD: 94020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("The Base Band sends this value as a response to a " 94120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "request for IMSI detach sent over the control " 94220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "channel uplink (see section 7.6.1)."); 94320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 94420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_MDM: 94520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_MDM; 94620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = MDM_DL; 94720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 94820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_DIAG: 94920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_DIAG; 95020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = DIAG_DL; 95120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 95220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_APP1: 95320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_APP1; 95420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = APP1_DL; 95520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 95620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_APP2: 95720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_APP2; 95820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = APP2_DL; 959661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel if (dc->state == NOZOMI_STATE_ALLOCATED) { 960661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel /* 961661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel * After card initialization the flow control 962661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel * received for APP2 is always the last 963661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel */ 964661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->state = NOZOMI_STATE_READY; 965661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dev_info(&dc->pdev->dev, "Device READY!\n"); 966661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel } 96720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 96820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel default: 96920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 97020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "ERROR: flow control received for non-existing port\n"); 97120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 97220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel }; 97320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 97420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("0x%04X->0x%04X", *((u16 *)&dc->port[port].ctrl_dl), 97520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *((u16 *)&ctrl_dl)); 97620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 97720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel old_ctrl = dc->port[port].ctrl_dl; 97820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].ctrl_dl = ctrl_dl; 97920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 98020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.CTS == 1 && ctrl_dl.CTS == 0) { 98120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Disable interrupt (0x%04X) on port: %d", 98220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier, port); 98320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel disable_transmit_ul(port, dc); 98420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 98520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (old_ctrl.CTS == 0 && ctrl_dl.CTS == 1) { 98620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 987e64c026dd09b73faf20707711402fc5ed55a8e70Stefani Seibold if (kfifo_len(&dc->port[port].fifo_ul)) { 98820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Enable interrupt (0x%04X) on port: %d", 98920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier, port); 99020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Data in buffer [%d], enable transmit! ", 991e64c026dd09b73faf20707711402fc5ed55a8e70Stefani Seibold kfifo_len(&dc->port[port].fifo_ul)); 99220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(port, dc); 99320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 99420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("No data in buffer..."); 99520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 99620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 99720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 99820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (*(u16 *)&old_ctrl == *(u16 *)&ctrl_dl) { 99920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1(" No change in mctrl"); 100020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 100120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 100220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Update statistics */ 100320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.CTS != ctrl_dl.CTS) 100420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.cts++; 100520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.DSR != ctrl_dl.DSR) 100620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.dsr++; 100720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.RI != ctrl_dl.RI) 100820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.rng++; 100920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.DCD != ctrl_dl.DCD) 101020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.dcd++; 101120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 101220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel wake_up_interruptible(&dc->port[port].tty_wait); 101320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 101420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("port: %d DCD(%d), CTS(%d), RI(%d), DSR(%d)", 101520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port, 101620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.dcd, dc->port[port].tty_icount.cts, 101720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.rng, dc->port[port].tty_icount.dsr); 101820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 101920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 102020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 102120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 102220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic enum ctrl_port_type port2ctrl(enum port_type port, 102320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel const struct nozomi *dc) 102420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 102520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (port) { 102620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_MDM: 102720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_MDM; 102820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_DIAG: 102920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_DIAG; 103020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_APP1: 103120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_APP1; 103220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_APP2: 103320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_APP2; 103420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel default: 103520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 103620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "ERROR: send flow control " \ 103720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "received for non-existing port\n"); 103820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel }; 103920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_ERROR; 104020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 104120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 104220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 104320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Send flow control, can only update one channel at a time 104420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - If we have updated all flow control 104520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - If we need to update more flow control, ack current enable more 104620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 104720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int send_flow_control(struct nozomi *dc) 104820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 104920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 i, more_flow_control_to_be_updated = 0; 105020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 *ctrl; 105120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 105220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = PORT_MDM; i < MAX_PORT; i++) { 105320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (dc->port[i].update_flow_control) { 105420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (more_flow_control_to_be_updated) { 105520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* We have more flow control to be updated */ 105620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 105720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 105820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[i].ctrl_ul.port = port2ctrl(i, dc); 105920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl = (u16 *)&dc->port[i].ctrl_ul; 106020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_CTRL].ul_addr[0], \ 106120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (u32 *) ctrl, 2); 106220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[i].update_flow_control = 0; 106320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel more_flow_control_to_be_updated = 1; 106420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 106520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 106620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 106720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 106820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 106920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 1070e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel * Handle downlink data, ports that are handled are modem and diagnostics 107120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - ok 107220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - toggle fields are out of sync 107320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 107420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int handle_data_dl(struct nozomi *dc, enum port_type port, u8 *toggle, 107520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 read_iir, u16 mask1, u16 mask2) 107620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 107720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (*toggle == 0 && read_iir & mask1) { 107820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 107920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask1, dc->reg_fcr); 108020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 108120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 108220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 108320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & mask2) { 108420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 108520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask2, dc->reg_fcr); 108620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 108720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 108820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 108920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (*toggle == 1 && read_iir & mask2) { 109020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 109120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask2, dc->reg_fcr); 109220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 109320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 109420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 109520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & mask1) { 109620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 109720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask1, dc->reg_fcr); 109820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 109920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 110020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 110120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 110220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "port out of sync!, toggle:%d\n", 110320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle); 110420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 110520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 110620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 110720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 110820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 110920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 111020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Handle uplink data, this is currently for the modem port 111120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - ok 111220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - toggle field are out of sync 111320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 111420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int handle_data_ul(struct nozomi *dc, enum port_type port, u16 read_iir) 111520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 111620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 *toggle = &(dc->port[port].toggle_ul); 111720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 111820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (*toggle == 0 && read_iir & MDM_UL1) { 111920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 112020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 112120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 112220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL1, dc->reg_fcr); 112320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 112420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 112520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 112620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 112720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 112820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_UL2) { 112920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 113020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 113120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 113220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL2, dc->reg_fcr); 113320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 113420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 113520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 113620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 113720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 113820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 113920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (*toggle == 1 && read_iir & MDM_UL2) { 114020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 114120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 114220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 114320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL2, dc->reg_fcr); 114420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 114520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 114620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 114720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 114820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 114920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_UL1) { 115020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 115120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 115220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 115320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL1, dc->reg_fcr); 115420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 115520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 115620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 115720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 115820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 115920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 116020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(read_iir & MDM_UL, dc->reg_fcr); 116120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "port out of sync!\n"); 116220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 116320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 116420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 116520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 116620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 116720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic irqreturn_t interrupt_handler(int irq, void *dev_id) 116820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 116920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = dev_id; 117020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int a; 117120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 read_iir; 117220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 117320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc) 117420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return IRQ_NONE; 117520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 117620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock(&dc->spin_mutex); 117720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_iir = readw(dc->reg_iir); 117820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 117920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Card removed */ 118020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir == (u16)-1) 118120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto none; 118220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 118320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Just handle interrupt enabled in IER 118420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * (by masking with dc->last_ier) 118520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 118620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_iir &= dc->last_ier; 118720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 118820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir == 0) 118920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto none; 119020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 119120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 119220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG4("%s irq:0x%04X, prev:0x%04X", interrupt2str(read_iir), read_iir, 119320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier); 119420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 119520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & RESET) { 119620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!nozomi_read_config_table(dc))) { 119720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0x0; 119820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 119920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Could not read status from " 120020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "card, we should disable interface\n"); 120120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 120220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(RESET, dc->reg_fcr); 120320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 120420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* No more useful info if this was the reset interrupt. */ 120520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 120620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 120720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & CTRL_UL) { 120820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("CTRL_UL"); 120920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~CTRL_UL; 121020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 121120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_flow_control(dc)) { 121220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(CTRL_UL, dc->reg_fcr); 121320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | CTRL_UL; 121420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 121520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 121620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 121720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & CTRL_DL) { 121820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel receive_flow_control(dc); 121920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(CTRL_DL, dc->reg_fcr); 122020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 122120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_DL) { 122220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!handle_data_dl(dc, PORT_MDM, 122320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel &(dc->port[PORT_MDM].toggle_dl), read_iir, 122420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel MDM_DL1, MDM_DL2)) { 122520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "MDM_DL out of sync!\n"); 122620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 122720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 122820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 122920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_UL) { 123020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!handle_data_ul(dc, PORT_MDM, read_iir)) { 123120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "MDM_UL out of sync!\n"); 123220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 123320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 123420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 123520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & DIAG_DL) { 123620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!handle_data_dl(dc, PORT_DIAG, 123720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel &(dc->port[PORT_DIAG].toggle_dl), read_iir, 123820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DIAG_DL1, DIAG_DL2)) { 123920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "DIAG_DL out of sync!\n"); 124020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 124120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 124220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 124320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & DIAG_UL) { 124420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~DIAG_UL; 124520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 124620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(PORT_DIAG, dc)) { 124720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(DIAG_UL, dc->reg_fcr); 124820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | DIAG_UL; 124920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 125020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 125120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 125220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP1_DL) { 125320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(PORT_APP1, dc)) 125420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP1_DL, dc->reg_fcr); 125520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 125620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP1_UL) { 125720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~APP1_UL; 125820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 125920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(PORT_APP1, dc)) { 126020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP1_UL, dc->reg_fcr); 126120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | APP1_UL; 126220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 126320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 126420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 126520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP2_DL) { 126620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(PORT_APP2, dc)) 126720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP2_DL, dc->reg_fcr); 126820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 126920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP2_UL) { 127020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~APP2_UL; 127120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 127220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(PORT_APP2, dc)) { 127320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP2_UL, dc->reg_fcr); 127420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | APP2_UL; 127520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 127620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 127720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 127820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 127920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelexit_handler: 128020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock(&dc->spin_mutex); 128133dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox for (a = 0; a < NOZOMI_MAX_PORTS; a++) { 128233dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_struct *tty; 128333dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox if (test_and_clear_bit(a, &dc->flip)) { 128433dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty = tty_port_tty_get(&dc->port[a].port); 128533dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox if (tty) 128633dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_flip_buffer_push(tty); 128733dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 128833dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox } 128933dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox } 129020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return IRQ_HANDLED; 129120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelnone: 129220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock(&dc->spin_mutex); 129320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return IRQ_NONE; 129420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 129520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 129620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void nozomi_get_card_type(struct nozomi *dc) 129720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 129820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 129920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size = 0; 130020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 130120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < 6; i++) 130220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel size += pci_resource_len(dc->pdev, i); 130320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 130420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Assume card type F32_8 if no match */ 130520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->card_type = size == 2048 ? F32_2 : F32_8; 130620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 130720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_info(&dc->pdev->dev, "Card type is: %d\n", dc->card_type); 130820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 130920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 131020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void nozomi_setup_private_data(struct nozomi *dc) 131120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 131220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *offset = dc->base_addr + dc->card_type / 2; 131320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int i; 131420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 131520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->reg_fcr = (void __iomem *)(offset + R_FCR); 131620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->reg_iir = (void __iomem *)(offset + R_IIR); 131720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->reg_ier = (void __iomem *)(offset + R_IER); 131820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0; 131920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->flip = 0; 132020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 132120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].token_dl = MDM_DL; 132220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].token_dl = DIAG_DL; 132320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].token_dl = APP1_DL; 132420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].token_dl = APP2_DL; 132520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 132620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < MAX_PORT; i++) 132720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel init_waitqueue_head(&dc->port[i].tty_wait); 132820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 132920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 133020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic ssize_t card_type_show(struct device *dev, struct device_attribute *attr, 133120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char *buf) 133220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 133371e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); 133420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 133520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return sprintf(buf, "%d\n", dc->card_type); 133620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 1337e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidelstatic DEVICE_ATTR(card_type, S_IRUGO, card_type_show, NULL); 133820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 133920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr, 134020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char *buf) 134120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 134271e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); 134320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 134420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return sprintf(buf, "%u\n", dc->open_ttys); 134520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 1346e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidelstatic DEVICE_ATTR(open_ttys, S_IRUGO, open_ttys_show, NULL); 134720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 134820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void make_sysfs_files(struct nozomi *dc) 134920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 135020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (device_create_file(&dc->pdev->dev, &dev_attr_card_type)) 135120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 135220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "Could not create sysfs file for card_type\n"); 135320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (device_create_file(&dc->pdev->dev, &dev_attr_open_ttys)) 135420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 135520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "Could not create sysfs file for open_ttys\n"); 135620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 135720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 135820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void remove_sysfs_files(struct nozomi *dc) 135920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 136020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel device_remove_file(&dc->pdev->dev, &dev_attr_card_type); 136120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel device_remove_file(&dc->pdev->dev, &dev_attr_open_ttys); 136220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 136320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 136420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Allocate memory for one device */ 136520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int __devinit nozomi_card_init(struct pci_dev *pdev, 136620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel const struct pci_device_id *ent) 136720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 136820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel resource_size_t start; 136920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ret; 137020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = NULL; 137120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ndev_idx; 137220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 137320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 137420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_dbg(&pdev->dev, "Init, new card found\n"); 137520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 137620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (ndev_idx = 0; ndev_idx < ARRAY_SIZE(ndevs); ndev_idx++) 137720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!ndevs[ndev_idx]) 137820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 137920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 138020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ndev_idx >= ARRAY_SIZE(ndevs)) { 138120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "no free tty range for this card left\n"); 138220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -EIO; 138320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err; 138420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 138520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 138620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc = kzalloc(sizeof(struct nozomi), GFP_KERNEL); 138720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!dc)) { 138820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Could not allocate memory\n"); 138920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -ENOMEM; 139020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_free; 139120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 139220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 139320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->pdev = pdev; 139420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 139520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = pci_enable_device(dc->pdev); 139620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 139720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Failed to enable PCI Device\n"); 139820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_free; 139920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 140020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 140120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = pci_request_regions(dc->pdev, NOZOMI_NAME); 140220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 140320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "I/O address 0x%04x already in use\n", 140420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (int) /* nozomi_private.io_addr */ 0); 140520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_disable_device; 140620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 140720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1408661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel start = pci_resource_start(dc->pdev, 0); 1409661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel if (start == 0) { 1410661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dev_err(&pdev->dev, "No I/O address for card detected\n"); 1411661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel ret = -ENODEV; 1412661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel goto err_rel_regs; 1413661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel } 1414661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1415661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel /* Find out what card type it is */ 1416661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel nozomi_get_card_type(dc); 1417661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 141824cb233520f01971d6d873cb52c64bbbb0665ac0Alan Cox dc->base_addr = ioremap_nocache(start, dc->card_type); 141920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc->base_addr) { 142020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Unable to map card MMIO\n"); 142120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -ENODEV; 142220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_rel_regs; 142320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 142420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 142520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->send_buf = kmalloc(SEND_BUF_MAX, GFP_KERNEL); 142620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc->send_buf) { 142720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Could not allocate send buffer?\n"); 142820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -ENOMEM; 142920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_free_sbuf; 143020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 143120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14329842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold for (i = PORT_MDM; i < MAX_PORT; i++) { 14339842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold if (kfifo_alloc(&dc->port[i].fifo_ul, 14349842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold FIFO_BUFFER_SIZE_UL, GFP_ATOMIC)) { 14359842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold dev_err(&pdev->dev, 14369842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold "Could not allocate kfifo buffer\n"); 14379842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold ret = -ENOMEM; 14389842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold goto err_free_kfifo; 14399842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold } 14409842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold } 14419842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold 144220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_init(&dc->spin_mutex); 144320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 144420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel nozomi_setup_private_data(dc); 144520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 144620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Disable all interrupts */ 144720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0; 144820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 144920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 145020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = request_irq(pdev->irq, &interrupt_handler, IRQF_SHARED, 145120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel NOZOMI_NAME, dc); 145220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(ret)) { 145320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq); 14549842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold goto err_free_kfifo; 145520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 145620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 145720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("base_addr: %p", dc->base_addr); 145820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 145920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel make_sysfs_files(dc); 146020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 146120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->index_start = ndev_idx * MAX_PORT; 146220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ndevs[ndev_idx] = dc; 146320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1464661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel pci_set_drvdata(pdev, dc); 1465661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1466661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel /* Enable RESET interrupt */ 1467661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->last_ier = RESET; 1468661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel iowrite16(dc->last_ier, dc->reg_ier); 1469661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1470661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->state = NOZOMI_STATE_ENABLED; 1471661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 147220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < MAX_PORT; i++) { 14739842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold struct device *tty_dev; 1474266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = &dc->port[i]; 1475266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox port->dc = dc; 1476266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox mutex_init(&port->tty_sem); 1477266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox tty_port_init(&port->port); 1478266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox port->port.ops = &noz_tty_port_ops; 14799842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold tty_dev = tty_register_device(ntty_driver, dc->index_start + i, 148020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel &pdev->dev); 14819842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold 14829842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold if (IS_ERR(tty_dev)) { 14839842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold ret = PTR_ERR(tty_dev); 14849842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold dev_err(&pdev->dev, "Could not allocate tty?\n"); 14859842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold goto err_free_tty; 14869842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold } 148720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 14889842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold 148920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 149020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14919842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibolderr_free_tty: 14929842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i) 14939842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold tty_unregister_device(ntty_driver, i); 14949842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibolderr_free_kfifo: 14959842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold for (i = 0; i < MAX_PORT; i++) 14969842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold kfifo_free(&dc->port[i].fifo_ul); 149720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_free_sbuf: 149820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc->send_buf); 149920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel iounmap(dc->base_addr); 150020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_rel_regs: 150120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_release_regions(pdev); 150220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_disable_device: 150320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_disable_device(pdev); 150420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_free: 150520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc); 150620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr: 150720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ret; 150820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 150920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 151020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void __devexit tty_exit(struct nozomi *dc) 151120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 151220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int i; 151320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 151420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1(" "); 151520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 151633dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox for (i = 0; i < MAX_PORT; ++i) { 151733dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_struct *tty = tty_port_tty_get(&dc->port[i].port); 151833dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox if (tty && list_empty(&tty->hangup_work.entry)) 151933dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_hangup(tty); 152033dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 152133dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox } 152233dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox /* Racy below - surely should wait for scheduled work to be done or 152333dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox complete off a hangup method ? */ 152420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel while (dc->open_ttys) 152520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel msleep(1); 152620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i) 152720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_unregister_device(ntty_driver, i); 152820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 152920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 153020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Deallocate memory for one device */ 153120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void __devexit nozomi_card_exit(struct pci_dev *pdev) 153220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 153320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 153420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_ul ctrl; 153520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = pci_get_drvdata(pdev); 153620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 153720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Disable all interrupts */ 153820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0; 153920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 154020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 154120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_exit(dc); 154220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 154320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Send 0x0001, command card to resend the reset token. */ 154420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* This is to get the reset when the module is reloaded. */ 154520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.port = 0x00; 154620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.reserved = 0; 154720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.RTS = 0; 154820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.DTR = 1; 154920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("sending flow control 0x%04X", *((u16 *)&ctrl)); 155020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 155120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Setup dc->reg addresses to we can use defines here */ 155220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_CTRL].ul_addr[0], (u32 *)&ctrl, 2); 155320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(CTRL_UL, dc->reg_fcr); /* push the token to the card. */ 155420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 155520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel remove_sysfs_files(dc); 155620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 155720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel free_irq(pdev->irq, dc); 155820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 155920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < MAX_PORT; i++) 156045465487897a1c6d508b14b904dc5777f7ec7e04Stefani Seibold kfifo_free(&dc->port[i].fifo_ul); 156120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc->send_buf); 156320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel iounmap(dc->base_addr); 156520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_release_regions(pdev); 156720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_disable_device(pdev); 156920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 157020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ndevs[dc->index_start / MAX_PORT] = NULL; 157120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 157220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc); 157320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 157420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 157520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void set_rts(const struct tty_struct *tty, int rts) 157620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 157720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = get_port_by_tty(tty); 157820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 157920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->ctrl_ul.RTS = rts; 158020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->update_flow_control = 1; 158120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); 158220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 158320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 158420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void set_dtr(const struct tty_struct *tty, int dtr) 158520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 158620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = get_port_by_tty(tty); 158720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 158820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("SETTING DTR index: %d, dtr: %d", tty->index, dtr); 158920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 159020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->ctrl_ul.DTR = dtr; 159120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->update_flow_control = 1; 159220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); 159320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 159420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 159520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 159620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * ---------------------------------------------------------------------------- 159720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * TTY code 159820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * ---------------------------------------------------------------------------- 159920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 160020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1601266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic int ntty_install(struct tty_driver *driver, struct tty_struct *tty) 160220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 160320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = get_port_by_tty(tty); 160420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 1605266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox int ret; 1606661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel if (!port || !dc || dc->state != NOZOMI_STATE_READY) 160720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return -ENODEV; 1608266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox ret = tty_init_termios(tty); 1609266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox if (ret == 0) { 1610266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox tty_driver_kref_get(driver); 1611ee78bb95b7bea08b7774a02073ea2bb45611a9e1Jiri Slaby tty->count++; 1612bf9c1fca9ae9a79ed209e7ab2c10b3862f3f6f72Jiri Slaby tty->driver_data = port; 1613266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox driver->ttys[tty->index] = tty; 161420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 1615266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox return ret; 161620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 161720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1618266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic void ntty_cleanup(struct tty_struct *tty) 1619266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1620266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox tty->driver_data = NULL; 1621266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 1622716da631ae91fc5e9f8d5815f8ef5fbfed862b80Alan Cox 1623266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic int ntty_activate(struct tty_port *tport, struct tty_struct *tty) 162420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 1625266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = container_of(tport, struct port, port); 1626266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct nozomi *dc = port->dc; 162720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 162820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1629266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox DBG1("open: %d", port->token_dl); 1630266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox spin_lock_irqsave(&dc->spin_mutex, flags); 1631266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox dc->last_ier = dc->last_ier | port->token_dl; 1632266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox writew(dc->last_ier, dc->reg_ier); 1633266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox dc->open_ttys++; 1634266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox spin_unlock_irqrestore(&dc->spin_mutex, flags); 1635266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox printk("noz: activated %d: %p\n", tty->index, tport); 1636266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox return 0; 1637266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 163820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1639266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic int ntty_open(struct tty_struct *tty, struct file *filp) 1640266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1641bf9c1fca9ae9a79ed209e7ab2c10b3862f3f6f72Jiri Slaby struct port *port = tty->driver_data; 1642266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox return tty_port_open(&port->port, tty, filp); 1643266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 164420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1645266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic void ntty_shutdown(struct tty_port *tport) 1646266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1647266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = container_of(tport, struct port, port); 1648266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct nozomi *dc = port->dc; 1649266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox unsigned long flags; 165020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1651266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox DBG1("close: %d", port->token_dl); 1652266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox spin_lock_irqsave(&dc->spin_mutex, flags); 1653266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox dc->last_ier &= ~(port->token_dl); 1654266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox writew(dc->last_ier, dc->reg_ier); 165520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->open_ttys--; 1656266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox spin_unlock_irqrestore(&dc->spin_mutex, flags); 1657266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox printk("noz: shutdown %p\n", tport); 1658266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 165920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1660266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic void ntty_close(struct tty_struct *tty, struct file *filp) 1661266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1662266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = tty->driver_data; 1663266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox if (port) 1664266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox tty_port_close(&port->port, tty, filp); 1665266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 1666266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox 1667266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic void ntty_hangup(struct tty_struct *tty) 1668266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1669266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = tty->driver_data; 1670266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox tty_port_hangup(&port->port); 167120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 167220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 167320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 167420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * called when the userspace process writes to the tty (/dev/noz*). 167520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Data is inserted into a fifo, which is then read and transfered to the modem. 167620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 167720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_write(struct tty_struct *tty, const unsigned char *buffer, 167820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int count) 167920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 168020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int rval = -EINVAL; 168120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 168220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 168320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 168420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 168520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* DBG1( "WRITEx: %d, index = %d", count, index); */ 168620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 168720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc || !port) 168820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return -ENODEV; 168920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1690e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox mutex_lock(&port->tty_sem); 169120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 169233dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox if (unlikely(!port->port.count)) { 169320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1(" "); 169420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit; 169520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 169620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 16977acd72eb85f1c7a15e8b5eb554994949241737f1Stefani Seibold rval = kfifo_in(&port->fifo_ul, (unsigned char *)buffer, count); 169820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 169920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* notify card */ 170020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(dc == NULL)) { 170120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("No device context?"); 170220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit; 170320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 170420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 170520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 170620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* CTS is only valid on the modem channel */ 170720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port == &(dc->port[PORT_MDM])) { 170820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port->ctrl_dl.CTS) { 170920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG4("Enable interrupt"); 171020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(tty->index % MAX_PORT, dc); 171120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 171220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 171320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "CTS not active on modem port?\n"); 171420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 171520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 171620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(tty->index % MAX_PORT, dc); 171720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 171820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 171920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 172020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelexit: 172120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel mutex_unlock(&port->tty_sem); 172220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return rval; 172320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 172420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 172520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 172620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Calculate how much is left in device 172720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * This method is called by the upper tty layer. 172820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * #according to sources N_TTY.c it expects a value >= 0 and 172920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * does not check for negative values. 1730e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox * 1731e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox * If the port is unplugged report lots of room and let the bits 1732e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox * dribble away so we don't block anything. 173320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 173420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_write_room(struct tty_struct *tty) 173520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 173620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 1737e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox int room = 4096; 173871e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct nozomi *dc = get_dc_by_tty(tty); 173920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1740e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox if (dc) { 1741e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox mutex_lock(&port->tty_sem); 1742e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox if (port->port.count) 17434457d9845927b3c62b6e833be243d21d6ca7df47Stefani Seibold room = kfifo_avail(&port->fifo_ul); 1744e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox mutex_unlock(&port->tty_sem); 1745e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox } 174620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return room; 174720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 174820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 174920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Gets io control parameters */ 175060b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int ntty_tiocmget(struct tty_struct *tty) 175120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 175271e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct port *port = tty->driver_data; 175371e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct ctrl_dl *ctrl_dl = &port->ctrl_dl; 175471e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct ctrl_ul *ctrl_ul = &port->ctrl_ul; 175520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1756978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox /* Note: these could change under us but it is not clear this 1757978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox matters if so */ 175820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return (ctrl_ul->RTS ? TIOCM_RTS : 0) | 175920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_ul->DTR ? TIOCM_DTR : 0) | 176020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->DCD ? TIOCM_CAR : 0) | 176120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->RI ? TIOCM_RNG : 0) | 176220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->DSR ? TIOCM_DSR : 0) | 176320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->CTS ? TIOCM_CTS : 0); 176420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 176520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 176620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Sets io controls parameters */ 176720b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int ntty_tiocmset(struct tty_struct *tty, 176820b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Cox unsigned int set, unsigned int clear) 176920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 1770661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 1771661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel unsigned long flags; 1772661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1773661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 177420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (set & TIOCM_RTS) 177520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 1); 177620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel else if (clear & TIOCM_RTS) 177720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 0); 177820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 177920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (set & TIOCM_DTR) 178020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_dtr(tty, 1); 178120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel else if (clear & TIOCM_DTR) 178220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_dtr(tty, 0); 1783661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 178420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 178520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 178620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 178720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 178820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_cflags_changed(struct port *port, unsigned long flags, 178920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct async_icount *cprev) 179020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 179118bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const struct async_icount cnow = port->tty_icount; 179220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ret; 179320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 179420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = ((flags & TIOCM_RNG) && (cnow.rng != cprev->rng)) || 179520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ((flags & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || 179620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ((flags & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || 179720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ((flags & TIOCM_CTS) && (cnow.cts != cprev->cts)); 179820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 179920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *cprev = cnow; 180020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 180120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ret; 180220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 180320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 18040587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Coxstatic int ntty_tiocgicount(struct tty_struct *tty, 18050587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox struct serial_icounter_struct *icount) 180620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 18070587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox struct port *port = tty->driver_data; 180818bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const struct async_icount cnow = port->tty_icount; 18090587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox 18100587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->cts = cnow.cts; 18110587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->dsr = cnow.dsr; 18120587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->rng = cnow.rng; 18130587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->dcd = cnow.dcd; 18140587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->rx = cnow.rx; 18150587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->tx = cnow.tx; 18160587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->frame = cnow.frame; 18170587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->overrun = cnow.overrun; 18180587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->parity = cnow.parity; 18190587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->brk = cnow.brk; 18200587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->buf_overrun = cnow.buf_overrun; 18210587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox return 0; 182220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 182320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 18246caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxstatic int ntty_ioctl(struct tty_struct *tty, 182520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int cmd, unsigned long arg) 182620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 182720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 182820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int rval = -ENOIOCTLCMD; 182920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 183020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("******** IOCTL, cmd: %d", cmd); 183120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 183220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (cmd) { 183320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case TIOCMIWAIT: { 183420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct async_icount cprev = port->tty_icount; 183520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 183620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel rval = wait_event_interruptible(port->tty_wait, 183720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_cflags_changed(port, arg, &cprev)); 183820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 18390587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox } 184020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel default: 184120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("ERR: 0x%08X, %d", cmd, cmd); 184220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 184320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel }; 184420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 184520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return rval; 184620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 184720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 184820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 184920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Called by the upper tty layer when tty buffers are ready 185020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * to receive data again after a call to throttle. 185120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 185220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void ntty_unthrottle(struct tty_struct *tty) 185320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 185420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 185520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 185620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 185720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("UNTHROTTLE"); 185820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 185920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_dl(tty->index % MAX_PORT, dc); 186020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 1); 186120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 186220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 186320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 186420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 186520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 186620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Called by the upper tty layer when the tty buffers are almost full. 186720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * The driver should stop send more data. 186820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 186920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void ntty_throttle(struct tty_struct *tty) 187020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 187120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 187220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 187320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 187420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("THROTTLE"); 187520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 187620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 0); 187720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 187820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 187920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 188020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Returns number of chars in buffer, called by tty layer */ 188120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic s32 ntty_chars_in_buffer(struct tty_struct *tty) 188220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 188320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 188420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 188523198fda7182969b619613a555f8645fdc3dc334Alan Cox s32 rval = 0; 188620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 188720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!dc || !port)) { 188820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_in_buffer; 188920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 189020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 189133dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox if (unlikely(!port->port.count)) { 189220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "No tty open?\n"); 189320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_in_buffer; 189420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 189520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1896e64c026dd09b73faf20707711402fc5ed55a8e70Stefani Seibold rval = kfifo_len(&port->fifo_ul); 189720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 189820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelexit_in_buffer: 189920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return rval; 190020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 190120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1902266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic const struct tty_port_operations noz_tty_port_ops = { 1903266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .activate = ntty_activate, 1904266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .shutdown = ntty_shutdown, 1905266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox}; 1906266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox 190718bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidelstatic const struct tty_operations tty_ops = { 190820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .ioctl = ntty_ioctl, 190920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .open = ntty_open, 191020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .close = ntty_close, 1911266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .hangup = ntty_hangup, 191220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .write = ntty_write, 191320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .write_room = ntty_write_room, 191420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .unthrottle = ntty_unthrottle, 191520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .throttle = ntty_throttle, 191620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .chars_in_buffer = ntty_chars_in_buffer, 191720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .tiocmget = ntty_tiocmget, 191820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .tiocmset = ntty_tiocmset, 19190587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox .get_icount = ntty_tiocgicount, 1920266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .install = ntty_install, 1921266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .cleanup = ntty_cleanup, 192220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 192320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 192420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Module initialization */ 192520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic struct pci_driver nozomi_driver = { 192620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .name = NOZOMI_NAME, 192720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .id_table = nozomi_pci_tbl, 192820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .probe = nozomi_card_init, 192920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .remove = __devexit_p(nozomi_card_exit), 193020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 193120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 193220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic __init int nozomi_init(void) 193320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 193420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ret; 193520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 193620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_INFO "Initializing %s\n", VERSION_STRING); 193720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 193820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver = alloc_tty_driver(NTTY_TTY_MAXMINORS); 193920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!ntty_driver) 194020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return -ENOMEM; 194120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 194220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->owner = THIS_MODULE; 194320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->driver_name = NOZOMI_NAME_TTY; 194420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->name = "noz"; 194520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->major = 0; 194620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->type = TTY_DRIVER_TYPE_SERIAL; 194720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->subtype = SERIAL_TYPE_NORMAL; 194820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 194920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios = tty_std_termios; 195020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | \ 195120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel HUPCL | CLOCAL; 195220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios.c_ispeed = 115200; 195320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios.c_ospeed = 115200; 195420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_set_operations(ntty_driver, &tty_ops); 195520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 195620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = tty_register_driver(ntty_driver); 195720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 195820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_ERR "Nozomi: failed to register ntty driver\n"); 195920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto free_tty; 196020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 196120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 196220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = pci_register_driver(&nozomi_driver); 196320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 196420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_ERR "Nozomi: can't register pci driver\n"); 196520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto unr_tty; 196620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 196720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 196820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 196920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelunr_tty: 197020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_unregister_driver(ntty_driver); 197120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelfree_tty: 197220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel put_tty_driver(ntty_driver); 197320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ret; 197420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 197520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 197620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic __exit void nozomi_exit(void) 197720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 197820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_INFO "Unloading %s\n", DRIVER_DESC); 197920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_unregister_driver(&nozomi_driver); 198020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_unregister_driver(ntty_driver); 198120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel put_tty_driver(ntty_driver); 198220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 198320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 198420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelmodule_init(nozomi_init); 198520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelmodule_exit(nozomi_exit); 198620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 198720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelmodule_param(debug, int, S_IRUGO | S_IWUSR); 198820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 198920fd1e3bea554620d489f3542496639c1babe0b3Frank SeidelMODULE_LICENSE("Dual BSD/GPL"); 199020fd1e3bea554620d489f3542496639c1babe0b3Frank SeidelMODULE_DESCRIPTION(DRIVER_DESC); 1991