nozomi.c revision 7fdc28931176a17ef0bdc5d35742925a155533c4
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 6420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define VERSION_STRING DRIVER_DESC " 2.1d (build date: " \ 6520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel __DATE__ " " __TIME__ ")" 6620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 6720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Macros definitions */ 6820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 6920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Default debug printout level */ 7020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_DEBUG_LEVEL 0x00 7120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 7220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define P_BUF_SIZE 128 7320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NFO(_err_flag_, args...) \ 7420fd1e3bea554620d489f3542496639c1babe0b3Frank Seideldo { \ 7520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char tmp[P_BUF_SIZE]; \ 7620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel snprintf(tmp, sizeof(tmp), ##args); \ 7720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(_err_flag_ "[%d] %s(): %s\n", __LINE__, \ 78bf9d89295233ae2ba7b312c78ee5657307b09f4cHarvey Harrison __func__, tmp); \ 7920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} while (0) 8020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 8120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG1(args...) D_(0x01, ##args) 8220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG2(args...) D_(0x02, ##args) 8320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG3(args...) D_(0x04, ##args) 8420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG4(args...) D_(0x08, ##args) 8520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG5(args...) D_(0x10, ##args) 8620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG6(args...) D_(0x20, ##args) 8720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG7(args...) D_(0x40, ##args) 8820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG8(args...) D_(0x80, ##args) 8920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 9020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef DEBUG 9120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Do we need this settable at runtime? */ 9220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int debug = NOZOMI_DEBUG_LEVEL; 9320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 94e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel#define D(lvl, args...) do \ 95e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \ 96e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel while (0) 9720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define D_(lvl, args...) D(lvl, ##args) 9820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 9920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* These printouts are always printed */ 10020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 10120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#else 10220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int debug; 10320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define D_(lvl, args...) 10420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 10520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 10620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* TODO: rewrite to optimize macros... */ 10720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 10820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define TMP_BUF_MAX 256 10920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 11020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DUMP(buf__,len__) \ 11120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel do { \ 11220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char tbuf[TMP_BUF_MAX] = {0};\ 11320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (len__ > 1) {\ 11420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel snprintf(tbuf, len__ > TMP_BUF_MAX ? TMP_BUF_MAX : len__, "%s", buf__);\ 11520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (tbuf[len__-2] == '\r') {\ 11620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tbuf[len__-2] = 'r';\ 11720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } \ 11820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("SENDING: '%s' (%d+n)", tbuf, len__);\ 11920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else {\ 12020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("SENDING: '%s' (%d)", tbuf, len__);\ 12120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } \ 12220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} while (0) 12320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 12420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Defines */ 12520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_NAME "nozomi" 12620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_NAME_TTY "nozomi_tty" 12720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DRIVER_DESC "Nozomi driver" 12820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 12920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NTTY_TTY_MAXMINORS 256 13020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NTTY_FIFO_BUFFER_SIZE 8192 13120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Must be power of 2 */ 13320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define FIFO_BUFFER_SIZE_UL 8192 13420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Size of tmp send buffer to card */ 13620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define SEND_BUF_MAX 1024 13720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define RECEIVE_BUF_MAX 4 13820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define R_IIR 0x0000 /* Interrupt Identity Register */ 14120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define R_FCR 0x0000 /* Flow Control Register */ 14220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define R_IER 0x0004 /* Interrupt Enable Register */ 14320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CONFIG_MAGIC 0xEFEFFEFE 14520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define TOGGLE_VALID 0x0000 14620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Definition of interrupt tokens */ 14820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_DL1 0x0001 14920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_UL1 0x0002 15020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_DL2 0x0004 15120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_UL2 0x0008 15220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_DL1 0x0010 15320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_DL2 0x0020 15420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_UL 0x0040 15520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP1_DL 0x0080 15620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP1_UL 0x0100 15720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP2_DL 0x0200 15820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP2_UL 0x0400 15920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DL 0x0800 16020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_UL 0x1000 16120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define RESET 0x8000 16220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 16320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_DL (MDM_DL1 | MDM_DL2) 16420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_UL (MDM_UL1 | MDM_UL2) 16520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_DL (DIAG_DL1 | DIAG_DL2) 16620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 16720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* modem signal definition */ 16820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DSR 0x0001 16920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DCD 0x0002 17020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_RI 0x0004 17120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_CTS 0x0008 17220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 17320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DTR 0x0001 17420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_RTS 0x0002 17520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 17620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MAX_PORT 4 17720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_MAX_PORTS 5 17820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_MAX_CARDS (NTTY_TTY_MAXMINORS / MAX_PORT) 17920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 18020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Type definitions */ 18120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 18220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 18320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * There are two types of nozomi cards, 18420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * one with 2048 memory and with 8192 memory 18520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 18620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum card_type { 18720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel F32_2 = 2048, /* 512 bytes downlink + uplink * 2 -> 2048 */ 18820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel F32_8 = 8192, /* 3072 bytes downl. + 1024 bytes uplink * 2 -> 8192 */ 18920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 19020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 191661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel/* Initialization states a card can be in */ 192661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidelenum card_state { 193661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_UKNOWN = 0, 194661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_ENABLED = 1, /* pci device enabled */ 195661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_ALLOCATED = 2, /* config setup done */ 196661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_READY = 3, /* flowcontrols received */ 197661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel}; 198661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 19920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Two different toggle channels exist */ 20020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum channel_type { 20120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CH_A = 0, 20220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CH_B = 1, 20320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 20420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 20520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Port definition for the card regarding flow control */ 20620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum ctrl_port_type { 20720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_CMD = 0, 20820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_MDM = 1, 20920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_DIAG = 2, 21020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_APP1 = 3, 21120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_APP2 = 4, 21220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_ERROR = -1, 21320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 21420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 21520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Ports that the nozomi has */ 21620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum port_type { 21720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_MDM = 0, 21820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_DIAG = 1, 21920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_APP1 = 2, 22020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_APP2 = 3, 22120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_CTRL = 4, 22220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_ERROR = -1, 22320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 22420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 22520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef __BIG_ENDIAN 22620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Big endian */ 22720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 22820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct toggles { 229e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int enabled:5; /* 23020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Toggle fields are valid if enabled is 0, 23120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * else A-channels must always be used. 23220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 233e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int diag_dl:1; 234e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_dl:1; 235e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_ul:1; 23620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 23720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 23820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Configuration table to read at startup of card */ 23920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Is for now only needed during initialization phase */ 24020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct config_table { 24120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 signature; 24220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 product_information; 24320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 version; 24420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad3[3]; 24520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct toggles toggle; 24620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad1[4]; 24720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len1; /* 24820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * If this is 64, it can hold 24920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 60 bytes + 4 that is length field 25020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 25120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_start; 25220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 25320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len1; 25420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len2; /* 25520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * If this is 64, it can hold 25620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 60 bytes + 4 that is length field 25720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 25820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app1_len; 25920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 26020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len2; 26120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_ctrl_len; 26220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app2_len; 26320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad2[16]; 26420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len1; 26520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_start; 26620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_diag_len; 26720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len2; 26820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app1_len; 26920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app2_len; 27020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_ctrl_len; 27120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 27220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 27320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control downlink flags */ 27420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_dl { 27520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 276e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserved:4; 277e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int CTS:1; 278e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RI:1; 279e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DCD:1; 280e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DSR:1; 28120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 28220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 28320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control uplink flags */ 28420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_ul { 28520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 286e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserved:6; 287e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RTS:1; 288e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DTR:1; 28920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 29020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 29120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#else 29220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Little endian */ 29320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 29420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This represents the toggle information */ 29520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct toggles { 296e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_ul:1; 297e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_dl:1; 298e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int diag_dl:1; 299e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int enabled:5; /* 30020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Toggle fields are valid if enabled is 0, 30120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * else A-channels must always be used. 30220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 30320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 30420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 30520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Configuration table to read at startup of card */ 30620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct config_table { 30720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 signature; 30820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 version; 30920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 product_information; 31020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct toggles toggle; 31120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad1[7]; 31220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_start; 31320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len1; /* 31420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * If this is 64, it can hold 31520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 60 bytes + 4 that is length field 31620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 31720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len2; 31820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len1; 31920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len2; 32020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app1_len; 32120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app2_len; 32220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_ctrl_len; 32320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad2[16]; 32420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_start; 32520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len2; 32620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len1; 32720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_diag_len; 32820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app1_len; 32920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app2_len; 33020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_ctrl_len; 33120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 33220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 33320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control downlink flags */ 33420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_dl { 335e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DSR:1; 336e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DCD:1; 337e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RI:1; 338e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int CTS:1; 339e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserverd:4; 34020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 34120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 34220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 34320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control uplink flags */ 34420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_ul { 345e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DTR:1; 346e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RTS:1; 347e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserved:6; 34820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 34920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 35020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 35120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 35220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This holds all information that is needed regarding a port */ 35320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct port { 35433dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_port port; 35520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 update_flow_control; 35620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_ul ctrl_ul; 35720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_dl ctrl_dl; 35845465487897a1c6d508b14b904dc5777f7ec7e04Stefani Seibold struct kfifo fifo_ul; 35920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *dl_addr[2]; 36020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 dl_size[2]; 36120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 toggle_dl; 36220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *ul_addr[2]; 36320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 ul_size[2]; 36420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 toggle_ul; 36520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 token_dl; 36620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 36720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel wait_queue_head_t tty_wait; 36820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct async_icount tty_icount; 369266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox 370266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct nozomi *dc; 37120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 37220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 37320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Private data one for each card in the system */ 37420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct nozomi { 37520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *base_addr; 37620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flip; 37720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 37820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Pointers to registers */ 37920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *reg_iir; 38020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *reg_fcr; 38120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *reg_ier; 38220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 38320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 last_ier; 38420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enum card_type card_type; 38520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct config_table config_table; /* Configuration table */ 38620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct pci_dev *pdev; 38720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port port[NOZOMI_MAX_PORTS]; 38820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 *send_buf; 38920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 39020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spinlock_t spin_mutex; /* secures access to registers and tty */ 39120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 39220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int index_start; 393661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel enum card_state state; 39420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 open_ttys; 39520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 39620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 39720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This is a data packet that is read or written to/from card */ 39820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct buffer { 39920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size; /* size is the length of the data buffer */ 40020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 *data; 40120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 40220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 40320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Global variables */ 40418bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidelstatic const struct pci_device_id nozomi_pci_tbl[] __devinitconst = { 405b2a3dbc3ed401828c4de0f08d08d96d0f5ea5b0bAlan Cox {PCI_DEVICE(0x1931, 0x000c)}, /* Nozomi HSDPA */ 40620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel {}, 40720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 40820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 40920fd1e3bea554620d489f3542496639c1babe0b3Frank SeidelMODULE_DEVICE_TABLE(pci, nozomi_pci_tbl); 41020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 41120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic struct nozomi *ndevs[NOZOMI_MAX_CARDS]; 41220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic struct tty_driver *ntty_driver; 41320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 414266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic const struct tty_port_operations noz_tty_port_ops; 415266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox 41620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 41720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * find card by tty_index 41820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 41920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic inline struct nozomi *get_dc_by_tty(const struct tty_struct *tty) 42020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 42120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return tty ? ndevs[tty->index / MAX_PORT] : NULL; 42220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 42320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 42420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic inline struct port *get_port_by_tty(const struct tty_struct *tty) 42520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 42620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *ndev = get_dc_by_tty(tty); 42720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ndev ? &ndev->port[tty->index % MAX_PORT] : NULL; 42820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 42920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 43020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 43120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * TODO: 43220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -Optimize 43320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -Rewrite cleaner 43420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 43520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 43620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void read_mem32(u32 *buf, const void __iomem *mem_addr_start, 43720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size_bytes) 43820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 43920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 i = 0; 440782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro const u32 __iomem *ptr = mem_addr_start; 44120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 *buf16; 44220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 44320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!ptr || !buf)) 44420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto out; 44520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 44620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* shortcut for extremely often used cases */ 44720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (size_bytes) { 44820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 2: /* 2 bytes */ 44920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel buf16 = (u16 *) buf; 450782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro *buf16 = __le16_to_cpu(readw(ptr)); 45120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto out; 45220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 45320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 4: /* 4 bytes */ 454782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro *(buf) = __le32_to_cpu(readl(ptr)); 45520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto out; 45620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 45720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 45820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 45920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel while (i < size_bytes) { 46020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (size_bytes - i == 2) { 46120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Handle 2 bytes in the end */ 46220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel buf16 = (u16 *) buf; 463782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro *(buf16) = __le16_to_cpu(readw(ptr)); 46420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i += 2; 46520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 46620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Read 4 bytes */ 467782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro *(buf) = __le32_to_cpu(readl(ptr)); 46820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i += 4; 46920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 47020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel buf++; 47120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ptr++; 47220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 47320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelout: 47420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return; 47520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 47620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 47720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 47820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * TODO: 47920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -Optimize 48020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -Rewrite cleaner 48120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 48271e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardtstatic u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf, 48320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size_bytes) 48420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 48520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 i = 0; 486782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro u32 __iomem *ptr = mem_addr_start; 48771e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const u16 *buf16; 48820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 48920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!ptr || !buf)) 49020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 49120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 49220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* shortcut for extremely often used cases */ 49320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (size_bytes) { 49420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 2: /* 2 bytes */ 49571e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt buf16 = (const u16 *)buf; 496782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro writew(__cpu_to_le16(*buf16), ptr); 49720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 2; 49820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 49920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 1: /* 50020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * also needs to write 4 bytes in this case 50120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * so falling through.. 50220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 50320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 4: /* 4 bytes */ 504782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro writel(__cpu_to_le32(*buf), ptr); 50520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 4; 50620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 50720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 50820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 50920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel while (i < size_bytes) { 51020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (size_bytes - i == 2) { 51120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 2 bytes */ 51271e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt buf16 = (const u16 *)buf; 513782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro writew(__cpu_to_le16(*buf16), ptr); 51420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i += 2; 51520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 51620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 4 bytes */ 517782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro writel(__cpu_to_le32(*buf), ptr); 51820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i += 4; 51920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 52020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel buf++; 52120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ptr++; 52220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 52320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return i; 52420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 52520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 52620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Setup pointers to different channels and also setup buffer sizes. */ 52720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void setup_memory(struct nozomi *dc) 52820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 52920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *offset = dc->base_addr + dc->config_table.dl_start; 53020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* The length reported is including the length field of 4 bytes, 53120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * hence subtract with 4. 53220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 53320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel const u16 buff_offset = 4; 53420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 53520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Modem port dl configuration */ 53620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].dl_addr[CH_A] = offset; 53720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].dl_addr[CH_B] = 53820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_mdm_len1); 53920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].dl_size[CH_A] = 54020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_mdm_len1 - buff_offset; 54120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].dl_size[CH_B] = 54220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_mdm_len2 - buff_offset; 54320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 54420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Diag port dl configuration */ 54520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].dl_addr[CH_A] = 54620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_mdm_len2); 54720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].dl_size[CH_A] = 54820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_diag_len1 - buff_offset; 54920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].dl_addr[CH_B] = 55020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_diag_len1); 55120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].dl_size[CH_B] = 55220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_diag_len2 - buff_offset; 55320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 55420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* App1 port dl configuration */ 55520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].dl_addr[CH_A] = 55620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_diag_len2); 55720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].dl_size[CH_A] = 55820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_app1_len - buff_offset; 55920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 56020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* App2 port dl configuration */ 56120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].dl_addr[CH_A] = 56220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_app1_len); 56320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].dl_size[CH_A] = 56420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_app2_len - buff_offset; 56520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 56620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Ctrl dl configuration */ 56720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_CTRL].dl_addr[CH_A] = 56820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_app2_len); 56920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_CTRL].dl_size[CH_A] = 57020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_ctrl_len - buff_offset; 57120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 57220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel offset = dc->base_addr + dc->config_table.ul_start; 57320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 57420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Modem Port ul configuration */ 57520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].ul_addr[CH_A] = offset; 57620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].ul_size[CH_A] = 57720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_mdm_len1 - buff_offset; 57820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].ul_addr[CH_B] = 57920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_mdm_len1); 58020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].ul_size[CH_B] = 58120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_mdm_len2 - buff_offset; 58220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 58320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Diag port ul configuration */ 58420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].ul_addr[CH_A] = 58520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_mdm_len2); 58620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].ul_size[CH_A] = 58720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_diag_len - buff_offset; 58820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 58920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* App1 port ul configuration */ 59020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].ul_addr[CH_A] = 59120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_diag_len); 59220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].ul_size[CH_A] = 59320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_app1_len - buff_offset; 59420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 59520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* App2 port ul configuration */ 59620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].ul_addr[CH_A] = 59720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_app1_len); 59820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].ul_size[CH_A] = 59920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_app2_len - buff_offset; 60020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 60120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Ctrl ul configuration */ 60220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_CTRL].ul_addr[CH_A] = 60320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_app2_len); 60420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_CTRL].ul_size[CH_A] = 60520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_ctrl_len - buff_offset; 60620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 60720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 60820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Dump config table under initalization phase */ 60920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef DEBUG 61020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void dump_table(const struct nozomi *dc) 61120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 61220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("signature: 0x%08X", dc->config_table.signature); 61320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("version: 0x%04X", dc->config_table.version); 61420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("product_information: 0x%04X", \ 61520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.product_information); 61620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("toggle enabled: %d", dc->config_table.toggle.enabled); 61720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("toggle up_mdm: %d", dc->config_table.toggle.mdm_ul); 61820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("toggle dl_mdm: %d", dc->config_table.toggle.mdm_dl); 61920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("toggle dl_dbg: %d", dc->config_table.toggle.diag_dl); 62020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 62120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_start: 0x%04X", dc->config_table.dl_start); 62220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_mdm_len0: 0x%04X, %d", dc->config_table.dl_mdm_len1, 62320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_mdm_len1); 62420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_mdm_len1: 0x%04X, %d", dc->config_table.dl_mdm_len2, 62520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_mdm_len2); 62620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_diag_len0: 0x%04X, %d", dc->config_table.dl_diag_len1, 62720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_diag_len1); 62820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_diag_len1: 0x%04X, %d", dc->config_table.dl_diag_len2, 62920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_diag_len2); 63020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_app1_len: 0x%04X, %d", dc->config_table.dl_app1_len, 63120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_app1_len); 63220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_app2_len: 0x%04X, %d", dc->config_table.dl_app2_len, 63320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_app2_len); 63420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_ctrl_len: 0x%04X, %d", dc->config_table.dl_ctrl_len, 63520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_ctrl_len); 63620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_start: 0x%04X, %d", dc->config_table.ul_start, 63720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_start); 63820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_mdm_len[0]: 0x%04X, %d", dc->config_table.ul_mdm_len1, 63920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_mdm_len1); 64020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_mdm_len[1]: 0x%04X, %d", dc->config_table.ul_mdm_len2, 64120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_mdm_len2); 64220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_diag_len: 0x%04X, %d", dc->config_table.ul_diag_len, 64320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_diag_len); 64420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_app1_len: 0x%04X, %d", dc->config_table.ul_app1_len, 64520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_app1_len); 64620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_app2_len: 0x%04X, %d", dc->config_table.ul_app2_len, 64720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_app2_len); 64820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_ctrl_len: 0x%04X, %d", dc->config_table.ul_ctrl_len, 64920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_ctrl_len); 65020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 65120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#else 652e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidelstatic inline void dump_table(const struct nozomi *dc) { } 65320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 65420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 65520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 65620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Read configuration table from card under intalization phase 65720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Returns 1 if ok, else 0 65820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 65920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int nozomi_read_config_table(struct nozomi *dc) 66020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 66120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_mem32((u32 *) &dc->config_table, dc->base_addr + 0, 66220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel sizeof(struct config_table)); 66320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 66420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (dc->config_table.signature != CONFIG_MAGIC) { 66520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "ConfigTable Bad! 0x%08X != 0x%08X\n", 66620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.signature, CONFIG_MAGIC); 66720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 66820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 66920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 67020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if ((dc->config_table.version == 0) 67120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel || (dc->config_table.toggle.enabled == TOGGLE_VALID)) { 67220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 67320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Second phase, configuring card"); 67420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 67520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel setup_memory(dc); 67620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 67720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].toggle_ul = dc->config_table.toggle.mdm_ul; 67820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].toggle_dl = dc->config_table.toggle.mdm_dl; 67920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].toggle_dl = dc->config_table.toggle.diag_dl; 68020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("toggle ports: MDM UL:%d MDM DL:%d, DIAG DL:%d", 68120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].toggle_ul, 68220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].toggle_dl, dc->port[PORT_DIAG].toggle_dl); 68320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 68420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dump_table(dc); 68520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 68620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = PORT_MDM; i < MAX_PORT; i++) { 68720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel memset(&dc->port[i].ctrl_dl, 0, sizeof(struct ctrl_dl)); 68820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel memset(&dc->port[i].ctrl_ul, 0, sizeof(struct ctrl_ul)); 68920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 69020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 69120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Enable control channel */ 69220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | CTRL_DL; 69320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 69420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 695661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->state = NOZOMI_STATE_ALLOCATED; 69620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_info(&dc->pdev->dev, "Initialization OK!\n"); 69720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 69820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 69920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 70020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if ((dc->config_table.version > 0) 70120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel && (dc->config_table.toggle.enabled != TOGGLE_VALID)) { 70220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 offset = 0; 70320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("First phase: pushing upload buffers, clearing download"); 70420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 70520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_info(&dc->pdev->dev, "Version of card: %d\n", 70620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.version); 70720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 70820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Here we should disable all I/O over F32. */ 70920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel setup_memory(dc); 71020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 71120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 71220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * We should send ALL channel pair tokens back along 71320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * with reset token 71420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 71520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 71620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* push upload modem buffers */ 71720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_MDM].ul_addr[CH_A], 71820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (u32 *) &offset, 4); 71920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_MDM].ul_addr[CH_B], 72020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (u32 *) &offset, 4); 72120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 72220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL | DIAG_DL | MDM_DL, dc->reg_fcr); 72320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 72420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("First phase done"); 72520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 72620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 72720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 72820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 72920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 73020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Enable uplink interrupts */ 73120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void enable_transmit_ul(enum port_type port, struct nozomi *dc) 73220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 73371e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL}; 73420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 73520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 73620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier |= mask[port]; 73720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 73820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 73920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 74020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 74120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 74220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 74320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Disable uplink interrupts */ 74420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void disable_transmit_ul(enum port_type port, struct nozomi *dc) 74520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 74671e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = 74771e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL}; 74820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 74920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 75020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= mask[port]; 75120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 75220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 75320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 75420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 75520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 75620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 75720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Enable downlink interrupts */ 75820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void enable_transmit_dl(enum port_type port, struct nozomi *dc) 75920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 76071e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL}; 76120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 76220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 76320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier |= mask[port]; 76420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 76520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 76620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 76720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 76820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 76920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 77020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Disable downlink interrupts */ 77120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void disable_transmit_dl(enum port_type port, struct nozomi *dc) 77220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 77371e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = 77471e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL}; 77520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 77620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 77720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= mask[port]; 77820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 77920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 78020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 78120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 78220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 78320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 78420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 78520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - send buffer to card and ack. 78620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - don't ack, don't send buffer to card. 78720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 78833dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Coxstatic int send_data(enum port_type index, struct nozomi *dc) 78920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 79020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size = 0; 79133dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct port *port = &dc->port[index]; 79218bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const u8 toggle = port->toggle_ul; 79320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *addr = port->ul_addr[toggle]; 79418bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const u32 ul_size = port->ul_size[toggle]; 79533dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_struct *tty = tty_port_tty_get(&port->port); 79620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 79720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Get data from tty and place in buf for now */ 7987acd72eb85f1c7a15e8b5eb554994949241737f1Stefani Seibold size = kfifo_out(&port->fifo_ul, dc->send_buf, 79920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ul_size < SEND_BUF_MAX ? ul_size : SEND_BUF_MAX); 80020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 80120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (size == 0) { 80220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG4("No more data to send, disable link:"); 80333dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 80420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 80520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 80620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 80720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* DUMP(buf, size); */ 80820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 80920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Write length + data */ 81020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(addr, (u32 *) &size, 4); 81120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(addr + 4, (u32 *) dc->send_buf, size); 81220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 81320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (tty) 81420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_wakeup(tty); 81520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 81633dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 81720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 81820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 81920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 82020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* If all data has been read, return 1, else 0 */ 82120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int receive_data(enum port_type index, struct nozomi *dc) 82220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 82320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 buf[RECEIVE_BUF_MAX] = { 0 }; 82420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int size; 82520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 offset = 4; 82620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = &dc->port[index]; 82720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *addr = port->dl_addr[port->toggle_dl]; 82833dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_struct *tty = tty_port_tty_get(&port->port); 8299237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby int i, ret; 83020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 83120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!tty)) { 83220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("tty not open for port: %d?", index); 83320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 83420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 83520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 83620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_mem32((u32 *) &size, addr, 4); 83720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* DBG1( "%d bytes port: %d", size, index); */ 83820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 83920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (test_bit(TTY_THROTTLED, &tty->flags)) { 84020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("No room in tty, don't read data, don't ack interrupt, " 84120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "disable interrupt"); 84220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 84320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* disable interrupt in downlink... */ 84420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel disable_transmit_dl(index, dc); 8459237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby ret = 0; 8469237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby goto put; 84720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 84820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 84920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(size == 0)) { 85020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "size == 0?\n"); 8519237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby ret = 1; 8529237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby goto put; 85320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 85420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 85520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel while (size > 0) { 85620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_mem32((u32 *) buf, addr + offset, RECEIVE_BUF_MAX); 85720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 85820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (size == 1) { 85920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_insert_flip_char(tty, buf[0], TTY_NORMAL); 86020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel size = 0; 86120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (size < RECEIVE_BUF_MAX) { 86220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel size -= tty_insert_flip_string(tty, (char *) buf, size); 86320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 86420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i = tty_insert_flip_string(tty, \ 86520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (char *) buf, RECEIVE_BUF_MAX); 86620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel size -= i; 86720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel offset += i; 86820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 86920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 87020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 87120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_bit(index, &dc->flip); 8729237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby ret = 1; 8739237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slabyput: 87433dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 8759237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby return ret; 87620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 87720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 87820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Debug for interrupts */ 87920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef DEBUG 88020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic char *interrupt2str(u16 interrupt) 88120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 88220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel static char buf[TMP_BUF_MAX]; 88320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char *p = buf; 88420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 88520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_DL1 ? p += snprintf(p, TMP_BUF_MAX, "MDM_DL1 ") : NULL; 88620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 88720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "MDM_DL2 ") : NULL; 88820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 88920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_UL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "MDM_UL1 ") : NULL; 89120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_UL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "MDM_UL2 ") : NULL; 89320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 89420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & DIAG_DL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "DIAG_DL1 ") : NULL; 89620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & DIAG_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "DIAG_DL2 ") : NULL; 89820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 89920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & DIAG_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "DIAG_UL ") : NULL; 90120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 90220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP1_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP1_DL ") : NULL; 90420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP2_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP2_DL ") : NULL; 90620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 90720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP1_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP1_UL ") : NULL; 90920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP2_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 91020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP2_UL ") : NULL; 91120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 91220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & CTRL_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 91320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "CTRL_DL ") : NULL; 91420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & CTRL_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 91520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "CTRL_UL ") : NULL; 91620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 91720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & RESET ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 91820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "RESET ") : NULL; 91920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 92020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return buf; 92120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 92220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 92320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 92420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 92520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Receive flow control 92620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - If ok, else 0 92720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 92820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int receive_flow_control(struct nozomi *dc) 92920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 93020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enum port_type port = PORT_MDM; 93120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_dl ctrl_dl; 93220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_dl old_ctrl; 93320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 enable_ier = 0; 93420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 93520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_mem32((u32 *) &ctrl_dl, dc->port[PORT_CTRL].dl_addr[CH_A], 2); 93620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 93720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (ctrl_dl.port) { 93820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_CMD: 93920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("The Base Band sends this value as a response to a " 94020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "request for IMSI detach sent over the control " 94120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "channel uplink (see section 7.6.1)."); 94220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 94320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_MDM: 94420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_MDM; 94520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = MDM_DL; 94620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 94720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_DIAG: 94820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_DIAG; 94920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = DIAG_DL; 95020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 95120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_APP1: 95220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_APP1; 95320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = APP1_DL; 95420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 95520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_APP2: 95620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_APP2; 95720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = APP2_DL; 958661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel if (dc->state == NOZOMI_STATE_ALLOCATED) { 959661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel /* 960661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel * After card initialization the flow control 961661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel * received for APP2 is always the last 962661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel */ 963661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->state = NOZOMI_STATE_READY; 964661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dev_info(&dc->pdev->dev, "Device READY!\n"); 965661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel } 96620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 96720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel default: 96820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 96920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "ERROR: flow control received for non-existing port\n"); 97020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 97120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel }; 97220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 97320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("0x%04X->0x%04X", *((u16 *)&dc->port[port].ctrl_dl), 97420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *((u16 *)&ctrl_dl)); 97520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 97620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel old_ctrl = dc->port[port].ctrl_dl; 97720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].ctrl_dl = ctrl_dl; 97820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 97920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.CTS == 1 && ctrl_dl.CTS == 0) { 98020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Disable interrupt (0x%04X) on port: %d", 98120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier, port); 98220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel disable_transmit_ul(port, dc); 98320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 98420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (old_ctrl.CTS == 0 && ctrl_dl.CTS == 1) { 98520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 986e64c026dd09b73faf20707711402fc5ed55a8e70Stefani Seibold if (kfifo_len(&dc->port[port].fifo_ul)) { 98720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Enable interrupt (0x%04X) on port: %d", 98820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier, port); 98920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Data in buffer [%d], enable transmit! ", 990e64c026dd09b73faf20707711402fc5ed55a8e70Stefani Seibold kfifo_len(&dc->port[port].fifo_ul)); 99120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(port, dc); 99220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 99320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("No data in buffer..."); 99420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 99520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 99620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 99720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (*(u16 *)&old_ctrl == *(u16 *)&ctrl_dl) { 99820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1(" No change in mctrl"); 99920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 100020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 100120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Update statistics */ 100220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.CTS != ctrl_dl.CTS) 100320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.cts++; 100420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.DSR != ctrl_dl.DSR) 100520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.dsr++; 100620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.RI != ctrl_dl.RI) 100720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.rng++; 100820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.DCD != ctrl_dl.DCD) 100920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.dcd++; 101020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 101120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel wake_up_interruptible(&dc->port[port].tty_wait); 101220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 101320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("port: %d DCD(%d), CTS(%d), RI(%d), DSR(%d)", 101420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port, 101520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.dcd, dc->port[port].tty_icount.cts, 101620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.rng, dc->port[port].tty_icount.dsr); 101720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 101820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 101920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 102020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 102120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic enum ctrl_port_type port2ctrl(enum port_type port, 102220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel const struct nozomi *dc) 102320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 102420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (port) { 102520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_MDM: 102620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_MDM; 102720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_DIAG: 102820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_DIAG; 102920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_APP1: 103020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_APP1; 103120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_APP2: 103220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_APP2; 103320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel default: 103420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 103520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "ERROR: send flow control " \ 103620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "received for non-existing port\n"); 103720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel }; 103820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_ERROR; 103920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 104020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 104120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 104220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Send flow control, can only update one channel at a time 104320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - If we have updated all flow control 104420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - If we need to update more flow control, ack current enable more 104520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 104620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int send_flow_control(struct nozomi *dc) 104720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 104820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 i, more_flow_control_to_be_updated = 0; 104920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 *ctrl; 105020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 105120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = PORT_MDM; i < MAX_PORT; i++) { 105220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (dc->port[i].update_flow_control) { 105320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (more_flow_control_to_be_updated) { 105420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* We have more flow control to be updated */ 105520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 105620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 105720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[i].ctrl_ul.port = port2ctrl(i, dc); 105820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl = (u16 *)&dc->port[i].ctrl_ul; 105920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_CTRL].ul_addr[0], \ 106020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (u32 *) ctrl, 2); 106120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[i].update_flow_control = 0; 106220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel more_flow_control_to_be_updated = 1; 106320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 106420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 106520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 106620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 106720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 106820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 1069e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel * Handle downlink data, ports that are handled are modem and diagnostics 107020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - ok 107120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - toggle fields are out of sync 107220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 107320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int handle_data_dl(struct nozomi *dc, enum port_type port, u8 *toggle, 107420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 read_iir, u16 mask1, u16 mask2) 107520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 107620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (*toggle == 0 && read_iir & mask1) { 107720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 107820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask1, dc->reg_fcr); 107920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 108020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 108120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 108220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & mask2) { 108320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 108420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask2, dc->reg_fcr); 108520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 108620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 108720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 108820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (*toggle == 1 && read_iir & mask2) { 108920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 109020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask2, dc->reg_fcr); 109120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 109220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 109320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 109420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & mask1) { 109520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 109620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask1, dc->reg_fcr); 109720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 109820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 109920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 110020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 110120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "port out of sync!, toggle:%d\n", 110220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle); 110320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 110420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 110520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 110620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 110720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 110820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 110920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Handle uplink data, this is currently for the modem port 111020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - ok 111120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - toggle field are out of sync 111220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 111320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int handle_data_ul(struct nozomi *dc, enum port_type port, u16 read_iir) 111420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 111520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 *toggle = &(dc->port[port].toggle_ul); 111620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 111720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (*toggle == 0 && read_iir & MDM_UL1) { 111820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 111920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 112020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 112120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL1, dc->reg_fcr); 112220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 112320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 112420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 112520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 112620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 112720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_UL2) { 112820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 112920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 113020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 113120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL2, dc->reg_fcr); 113220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 113320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 113420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 113520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 113620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 113720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 113820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (*toggle == 1 && read_iir & MDM_UL2) { 113920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 114020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 114120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 114220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL2, dc->reg_fcr); 114320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 114420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 114520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 114620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 114720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 114820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_UL1) { 114920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 115020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 115120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 115220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL1, dc->reg_fcr); 115320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 115420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 115520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 115620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 115720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 115820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 115920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(read_iir & MDM_UL, dc->reg_fcr); 116020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "port out of sync!\n"); 116120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 116220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 116320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 116420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 116520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 116620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic irqreturn_t interrupt_handler(int irq, void *dev_id) 116720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 116820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = dev_id; 116920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int a; 117020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 read_iir; 117120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 117220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc) 117320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return IRQ_NONE; 117420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 117520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock(&dc->spin_mutex); 117620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_iir = readw(dc->reg_iir); 117720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 117820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Card removed */ 117920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir == (u16)-1) 118020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto none; 118120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 118220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Just handle interrupt enabled in IER 118320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * (by masking with dc->last_ier) 118420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 118520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_iir &= dc->last_ier; 118620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 118720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir == 0) 118820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto none; 118920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 119020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 119120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG4("%s irq:0x%04X, prev:0x%04X", interrupt2str(read_iir), read_iir, 119220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier); 119320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 119420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & RESET) { 119520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!nozomi_read_config_table(dc))) { 119620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0x0; 119720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 119820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Could not read status from " 119920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "card, we should disable interface\n"); 120020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 120120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(RESET, dc->reg_fcr); 120220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 120320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* No more useful info if this was the reset interrupt. */ 120420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 120520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 120620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & CTRL_UL) { 120720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("CTRL_UL"); 120820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~CTRL_UL; 120920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 121020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_flow_control(dc)) { 121120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(CTRL_UL, dc->reg_fcr); 121220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | CTRL_UL; 121320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 121420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 121520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 121620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & CTRL_DL) { 121720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel receive_flow_control(dc); 121820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(CTRL_DL, dc->reg_fcr); 121920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 122020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_DL) { 122120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!handle_data_dl(dc, PORT_MDM, 122220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel &(dc->port[PORT_MDM].toggle_dl), read_iir, 122320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel MDM_DL1, MDM_DL2)) { 122420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "MDM_DL out of sync!\n"); 122520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 122620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 122720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 122820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_UL) { 122920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!handle_data_ul(dc, PORT_MDM, read_iir)) { 123020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "MDM_UL out of sync!\n"); 123120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 123220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 123320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 123420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & DIAG_DL) { 123520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!handle_data_dl(dc, PORT_DIAG, 123620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel &(dc->port[PORT_DIAG].toggle_dl), read_iir, 123720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DIAG_DL1, DIAG_DL2)) { 123820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "DIAG_DL out of sync!\n"); 123920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 124020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 124120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 124220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & DIAG_UL) { 124320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~DIAG_UL; 124420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 124520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(PORT_DIAG, dc)) { 124620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(DIAG_UL, dc->reg_fcr); 124720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | DIAG_UL; 124820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 124920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 125020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 125120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP1_DL) { 125220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(PORT_APP1, dc)) 125320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP1_DL, dc->reg_fcr); 125420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 125520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP1_UL) { 125620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~APP1_UL; 125720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 125820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(PORT_APP1, dc)) { 125920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP1_UL, dc->reg_fcr); 126020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | APP1_UL; 126120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 126220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 126320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 126420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP2_DL) { 126520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(PORT_APP2, dc)) 126620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP2_DL, dc->reg_fcr); 126720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 126820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP2_UL) { 126920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~APP2_UL; 127020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 127120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(PORT_APP2, dc)) { 127220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP2_UL, dc->reg_fcr); 127320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | APP2_UL; 127420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 127520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 127620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 127720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 127820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelexit_handler: 127920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock(&dc->spin_mutex); 128033dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox for (a = 0; a < NOZOMI_MAX_PORTS; a++) { 128133dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_struct *tty; 128233dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox if (test_and_clear_bit(a, &dc->flip)) { 128333dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty = tty_port_tty_get(&dc->port[a].port); 128433dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox if (tty) 128533dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_flip_buffer_push(tty); 128633dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 128733dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox } 128833dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox } 128920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return IRQ_HANDLED; 129020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelnone: 129120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock(&dc->spin_mutex); 129220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return IRQ_NONE; 129320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 129420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 129520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void nozomi_get_card_type(struct nozomi *dc) 129620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 129720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 129820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size = 0; 129920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 130020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < 6; i++) 130120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel size += pci_resource_len(dc->pdev, i); 130220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 130320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Assume card type F32_8 if no match */ 130420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->card_type = size == 2048 ? F32_2 : F32_8; 130520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 130620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_info(&dc->pdev->dev, "Card type is: %d\n", dc->card_type); 130720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 130820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 130920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void nozomi_setup_private_data(struct nozomi *dc) 131020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 131120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *offset = dc->base_addr + dc->card_type / 2; 131220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int i; 131320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 131420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->reg_fcr = (void __iomem *)(offset + R_FCR); 131520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->reg_iir = (void __iomem *)(offset + R_IIR); 131620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->reg_ier = (void __iomem *)(offset + R_IER); 131720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0; 131820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->flip = 0; 131920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 132020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].token_dl = MDM_DL; 132120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].token_dl = DIAG_DL; 132220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].token_dl = APP1_DL; 132320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].token_dl = APP2_DL; 132420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 132520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < MAX_PORT; i++) 132620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel init_waitqueue_head(&dc->port[i].tty_wait); 132720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 132820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 132920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic ssize_t card_type_show(struct device *dev, struct device_attribute *attr, 133020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char *buf) 133120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 133271e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); 133320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 133420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return sprintf(buf, "%d\n", dc->card_type); 133520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 1336e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidelstatic DEVICE_ATTR(card_type, S_IRUGO, card_type_show, NULL); 133720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 133820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr, 133920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char *buf) 134020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 134171e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); 134220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 134320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return sprintf(buf, "%u\n", dc->open_ttys); 134420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 1345e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidelstatic DEVICE_ATTR(open_ttys, S_IRUGO, open_ttys_show, NULL); 134620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 134720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void make_sysfs_files(struct nozomi *dc) 134820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 134920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (device_create_file(&dc->pdev->dev, &dev_attr_card_type)) 135020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 135120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "Could not create sysfs file for card_type\n"); 135220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (device_create_file(&dc->pdev->dev, &dev_attr_open_ttys)) 135320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 135420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "Could not create sysfs file for open_ttys\n"); 135520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 135620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 135720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void remove_sysfs_files(struct nozomi *dc) 135820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 135920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel device_remove_file(&dc->pdev->dev, &dev_attr_card_type); 136020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel device_remove_file(&dc->pdev->dev, &dev_attr_open_ttys); 136120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 136220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 136320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Allocate memory for one device */ 136420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int __devinit nozomi_card_init(struct pci_dev *pdev, 136520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel const struct pci_device_id *ent) 136620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 136720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel resource_size_t start; 136820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ret; 136920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = NULL; 137020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ndev_idx; 137120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 137220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 137320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_dbg(&pdev->dev, "Init, new card found\n"); 137420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 137520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (ndev_idx = 0; ndev_idx < ARRAY_SIZE(ndevs); ndev_idx++) 137620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!ndevs[ndev_idx]) 137720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 137820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 137920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ndev_idx >= ARRAY_SIZE(ndevs)) { 138020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "no free tty range for this card left\n"); 138120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -EIO; 138220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err; 138320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 138420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 138520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc = kzalloc(sizeof(struct nozomi), GFP_KERNEL); 138620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!dc)) { 138720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Could not allocate memory\n"); 138820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -ENOMEM; 138920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_free; 139020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 139120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 139220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->pdev = pdev; 139320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 139420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = pci_enable_device(dc->pdev); 139520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 139620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Failed to enable PCI Device\n"); 139720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_free; 139820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 139920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 140020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = pci_request_regions(dc->pdev, NOZOMI_NAME); 140120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 140220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "I/O address 0x%04x already in use\n", 140320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (int) /* nozomi_private.io_addr */ 0); 140420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_disable_device; 140520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 140620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1407661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel start = pci_resource_start(dc->pdev, 0); 1408661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel if (start == 0) { 1409661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dev_err(&pdev->dev, "No I/O address for card detected\n"); 1410661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel ret = -ENODEV; 1411661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel goto err_rel_regs; 1412661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel } 1413661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1414661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel /* Find out what card type it is */ 1415661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel nozomi_get_card_type(dc); 1416661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 141724cb233520f01971d6d873cb52c64bbbb0665ac0Alan Cox dc->base_addr = ioremap_nocache(start, dc->card_type); 141820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc->base_addr) { 141920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Unable to map card MMIO\n"); 142020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -ENODEV; 142120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_rel_regs; 142220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 142320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 142420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->send_buf = kmalloc(SEND_BUF_MAX, GFP_KERNEL); 142520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc->send_buf) { 142620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Could not allocate send buffer?\n"); 142720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -ENOMEM; 142820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_free_sbuf; 142920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 143020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14319842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold for (i = PORT_MDM; i < MAX_PORT; i++) { 1432c29bd8d89c9423aed182dbfdb6527b576a2f3552Jiri Slaby if (kfifo_alloc(&dc->port[i].fifo_ul, FIFO_BUFFER_SIZE_UL, 1433c29bd8d89c9423aed182dbfdb6527b576a2f3552Jiri Slaby GFP_KERNEL)) { 14349842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold dev_err(&pdev->dev, 14359842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold "Could not allocate kfifo buffer\n"); 14369842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold ret = -ENOMEM; 14379842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold goto err_free_kfifo; 14389842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold } 14399842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold } 14409842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold 144120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_init(&dc->spin_mutex); 144220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 144320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel nozomi_setup_private_data(dc); 144420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 144520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Disable all interrupts */ 144620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0; 144720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 144820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 144920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = request_irq(pdev->irq, &interrupt_handler, IRQF_SHARED, 145020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel NOZOMI_NAME, dc); 145120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(ret)) { 145220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq); 14539842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold goto err_free_kfifo; 145420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 145520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 145620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("base_addr: %p", dc->base_addr); 145720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 145820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel make_sysfs_files(dc); 145920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 146020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->index_start = ndev_idx * MAX_PORT; 146120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ndevs[ndev_idx] = dc; 146220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1463661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel pci_set_drvdata(pdev, dc); 1464661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1465661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel /* Enable RESET interrupt */ 1466661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->last_ier = RESET; 1467661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel iowrite16(dc->last_ier, dc->reg_ier); 1468661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1469661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->state = NOZOMI_STATE_ENABLED; 1470661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 147120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < MAX_PORT; i++) { 14729842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold struct device *tty_dev; 1473266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = &dc->port[i]; 1474266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox port->dc = dc; 1475266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox tty_port_init(&port->port); 1476266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox port->port.ops = &noz_tty_port_ops; 14779842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold tty_dev = tty_register_device(ntty_driver, dc->index_start + i, 147820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel &pdev->dev); 14799842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold 14809842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold if (IS_ERR(tty_dev)) { 14819842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold ret = PTR_ERR(tty_dev); 14829842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold dev_err(&pdev->dev, "Could not allocate tty?\n"); 14839842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold goto err_free_tty; 14849842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold } 148520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 14869842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold 148720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 148820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14899842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibolderr_free_tty: 14909842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i) 14919842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold tty_unregister_device(ntty_driver, i); 14929842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibolderr_free_kfifo: 14939842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold for (i = 0; i < MAX_PORT; i++) 14949842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold kfifo_free(&dc->port[i].fifo_ul); 149520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_free_sbuf: 149620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc->send_buf); 149720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel iounmap(dc->base_addr); 149820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_rel_regs: 149920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_release_regions(pdev); 150020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_disable_device: 150120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_disable_device(pdev); 150220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_free: 150320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc); 150420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr: 150520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ret; 150620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 150720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 150820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void __devexit tty_exit(struct nozomi *dc) 150920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 151020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int i; 151120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 151220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1(" "); 151320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 151433dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox for (i = 0; i < MAX_PORT; ++i) { 151533dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_struct *tty = tty_port_tty_get(&dc->port[i].port); 151633dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox if (tty && list_empty(&tty->hangup_work.entry)) 151733dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_hangup(tty); 151833dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 151933dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox } 152033dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox /* Racy below - surely should wait for scheduled work to be done or 152133dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox complete off a hangup method ? */ 152220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel while (dc->open_ttys) 152320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel msleep(1); 152420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i) 152520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_unregister_device(ntty_driver, i); 152620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 152720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 152820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Deallocate memory for one device */ 152920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void __devexit nozomi_card_exit(struct pci_dev *pdev) 153020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 153120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 153220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_ul ctrl; 153320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = pci_get_drvdata(pdev); 153420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 153520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Disable all interrupts */ 153620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0; 153720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 153820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 153920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_exit(dc); 154020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 154120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Send 0x0001, command card to resend the reset token. */ 154220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* This is to get the reset when the module is reloaded. */ 154320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.port = 0x00; 154420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.reserved = 0; 154520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.RTS = 0; 154620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.DTR = 1; 154720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("sending flow control 0x%04X", *((u16 *)&ctrl)); 154820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 154920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Setup dc->reg addresses to we can use defines here */ 155020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_CTRL].ul_addr[0], (u32 *)&ctrl, 2); 155120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(CTRL_UL, dc->reg_fcr); /* push the token to the card. */ 155220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 155320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel remove_sysfs_files(dc); 155420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 155520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel free_irq(pdev->irq, dc); 155620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 155720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < MAX_PORT; i++) 155845465487897a1c6d508b14b904dc5777f7ec7e04Stefani Seibold kfifo_free(&dc->port[i].fifo_ul); 155920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc->send_buf); 156120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel iounmap(dc->base_addr); 156320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_release_regions(pdev); 156520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_disable_device(pdev); 156720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ndevs[dc->index_start / MAX_PORT] = NULL; 156920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 157020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc); 157120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 157220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 157320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void set_rts(const struct tty_struct *tty, int rts) 157420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 157520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = get_port_by_tty(tty); 157620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 157720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->ctrl_ul.RTS = rts; 157820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->update_flow_control = 1; 157920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); 158020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 158120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 158220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void set_dtr(const struct tty_struct *tty, int dtr) 158320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 158420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = get_port_by_tty(tty); 158520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 158620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("SETTING DTR index: %d, dtr: %d", tty->index, dtr); 158720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 158820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->ctrl_ul.DTR = dtr; 158920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->update_flow_control = 1; 159020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); 159120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 159220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 159320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 159420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * ---------------------------------------------------------------------------- 159520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * TTY code 159620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * ---------------------------------------------------------------------------- 159720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 159820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1599266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic int ntty_install(struct tty_driver *driver, struct tty_struct *tty) 160020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 160120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = get_port_by_tty(tty); 160220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 1603266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox int ret; 1604661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel if (!port || !dc || dc->state != NOZOMI_STATE_READY) 160520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return -ENODEV; 1606266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox ret = tty_init_termios(tty); 1607266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox if (ret == 0) { 1608266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox tty_driver_kref_get(driver); 1609ee78bb95b7bea08b7774a02073ea2bb45611a9e1Jiri Slaby tty->count++; 1610bf9c1fca9ae9a79ed209e7ab2c10b3862f3f6f72Jiri Slaby tty->driver_data = port; 1611266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox driver->ttys[tty->index] = tty; 161220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 1613266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox return ret; 161420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 161520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1616266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic void ntty_cleanup(struct tty_struct *tty) 1617266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1618266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox tty->driver_data = NULL; 1619266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 1620716da631ae91fc5e9f8d5815f8ef5fbfed862b80Alan Cox 1621266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic int ntty_activate(struct tty_port *tport, struct tty_struct *tty) 162220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 1623266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = container_of(tport, struct port, port); 1624266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct nozomi *dc = port->dc; 162520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 162620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1627266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox DBG1("open: %d", port->token_dl); 1628266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox spin_lock_irqsave(&dc->spin_mutex, flags); 1629266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox dc->last_ier = dc->last_ier | port->token_dl; 1630266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox writew(dc->last_ier, dc->reg_ier); 1631266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox dc->open_ttys++; 1632266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox spin_unlock_irqrestore(&dc->spin_mutex, flags); 1633266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox printk("noz: activated %d: %p\n", tty->index, tport); 1634266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox return 0; 1635266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 163620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1637266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic int ntty_open(struct tty_struct *tty, struct file *filp) 1638266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1639bf9c1fca9ae9a79ed209e7ab2c10b3862f3f6f72Jiri Slaby struct port *port = tty->driver_data; 1640266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox return tty_port_open(&port->port, tty, filp); 1641266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 164220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1643266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic void ntty_shutdown(struct tty_port *tport) 1644266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1645266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = container_of(tport, struct port, port); 1646266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct nozomi *dc = port->dc; 1647266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox unsigned long flags; 164820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1649266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox DBG1("close: %d", port->token_dl); 1650266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox spin_lock_irqsave(&dc->spin_mutex, flags); 1651266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox dc->last_ier &= ~(port->token_dl); 1652266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox writew(dc->last_ier, dc->reg_ier); 165320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->open_ttys--; 1654266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox spin_unlock_irqrestore(&dc->spin_mutex, flags); 1655266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox printk("noz: shutdown %p\n", tport); 1656266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 165720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1658266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic void ntty_close(struct tty_struct *tty, struct file *filp) 1659266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1660266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = tty->driver_data; 1661266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox if (port) 1662266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox tty_port_close(&port->port, tty, filp); 1663266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 1664266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox 1665266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic void ntty_hangup(struct tty_struct *tty) 1666266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1667266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = tty->driver_data; 1668266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox tty_port_hangup(&port->port); 166920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 167020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 167120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 167220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * called when the userspace process writes to the tty (/dev/noz*). 167325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Data is inserted into a fifo, which is then read and transferred to the modem. 167420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 167520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_write(struct tty_struct *tty, const unsigned char *buffer, 167620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int count) 167720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 167820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int rval = -EINVAL; 167920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 168020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 168120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 168220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 168320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* DBG1( "WRITEx: %d, index = %d", count, index); */ 168420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 168520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc || !port) 168620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return -ENODEV; 168720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 16887acd72eb85f1c7a15e8b5eb554994949241737f1Stefani Seibold rval = kfifo_in(&port->fifo_ul, (unsigned char *)buffer, count); 168920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 169020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* notify card */ 169120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(dc == NULL)) { 169220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("No device context?"); 169320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit; 169420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 169520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 169620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 169720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* CTS is only valid on the modem channel */ 169820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port == &(dc->port[PORT_MDM])) { 169920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port->ctrl_dl.CTS) { 170020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG4("Enable interrupt"); 170120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(tty->index % MAX_PORT, dc); 170220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 170320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 170420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "CTS not active on modem port?\n"); 170520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 170620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 170720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(tty->index % MAX_PORT, dc); 170820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 170920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 171020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 171120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelexit: 171220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return rval; 171320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 171420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 171520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 171620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Calculate how much is left in device 171720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * This method is called by the upper tty layer. 171820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * #according to sources N_TTY.c it expects a value >= 0 and 171920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * does not check for negative values. 1720e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox * 1721e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox * If the port is unplugged report lots of room and let the bits 1722e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox * dribble away so we don't block anything. 172320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 172420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_write_room(struct tty_struct *tty) 172520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 172620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 1727e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox int room = 4096; 172871e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct nozomi *dc = get_dc_by_tty(tty); 172920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 17307fdc28931176a17ef0bdc5d35742925a155533c4Jiri Slaby if (dc) 17316d742f655efe767dc77a099b57297fa417afc473Jiri Slaby room = kfifo_avail(&port->fifo_ul); 17327fdc28931176a17ef0bdc5d35742925a155533c4Jiri Slaby 173320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return room; 173420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 173520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 173620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Gets io control parameters */ 173760b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int ntty_tiocmget(struct tty_struct *tty) 173820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 173971e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct port *port = tty->driver_data; 174071e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct ctrl_dl *ctrl_dl = &port->ctrl_dl; 174171e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct ctrl_ul *ctrl_ul = &port->ctrl_ul; 174220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1743978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox /* Note: these could change under us but it is not clear this 1744978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox matters if so */ 174520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return (ctrl_ul->RTS ? TIOCM_RTS : 0) | 174620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_ul->DTR ? TIOCM_DTR : 0) | 174720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->DCD ? TIOCM_CAR : 0) | 174820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->RI ? TIOCM_RNG : 0) | 174920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->DSR ? TIOCM_DSR : 0) | 175020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->CTS ? TIOCM_CTS : 0); 175120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 175220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 175320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Sets io controls parameters */ 175420b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int ntty_tiocmset(struct tty_struct *tty, 175520b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Cox unsigned int set, unsigned int clear) 175620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 1757661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 1758661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel unsigned long flags; 1759661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1760661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 176120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (set & TIOCM_RTS) 176220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 1); 176320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel else if (clear & TIOCM_RTS) 176420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 0); 176520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 176620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (set & TIOCM_DTR) 176720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_dtr(tty, 1); 176820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel else if (clear & TIOCM_DTR) 176920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_dtr(tty, 0); 1770661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 177120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 177220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 177320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 177420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 177520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_cflags_changed(struct port *port, unsigned long flags, 177620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct async_icount *cprev) 177720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 177818bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const struct async_icount cnow = port->tty_icount; 177920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ret; 178020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 178120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = ((flags & TIOCM_RNG) && (cnow.rng != cprev->rng)) || 178220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ((flags & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || 178320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ((flags & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || 178420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ((flags & TIOCM_CTS) && (cnow.cts != cprev->cts)); 178520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 178620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *cprev = cnow; 178720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 178820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ret; 178920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 179020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 17910587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Coxstatic int ntty_tiocgicount(struct tty_struct *tty, 17920587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox struct serial_icounter_struct *icount) 179320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 17940587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox struct port *port = tty->driver_data; 179518bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const struct async_icount cnow = port->tty_icount; 17960587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox 17970587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->cts = cnow.cts; 17980587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->dsr = cnow.dsr; 17990587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->rng = cnow.rng; 18000587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->dcd = cnow.dcd; 18010587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->rx = cnow.rx; 18020587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->tx = cnow.tx; 18030587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->frame = cnow.frame; 18040587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->overrun = cnow.overrun; 18050587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->parity = cnow.parity; 18060587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->brk = cnow.brk; 18070587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->buf_overrun = cnow.buf_overrun; 18080587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox return 0; 180920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 181020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 18116caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxstatic int ntty_ioctl(struct tty_struct *tty, 181220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int cmd, unsigned long arg) 181320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 181420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 181520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int rval = -ENOIOCTLCMD; 181620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 181720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("******** IOCTL, cmd: %d", cmd); 181820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 181920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (cmd) { 182020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case TIOCMIWAIT: { 182120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct async_icount cprev = port->tty_icount; 182220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 182320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel rval = wait_event_interruptible(port->tty_wait, 182420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_cflags_changed(port, arg, &cprev)); 182520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 18260587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox } 182720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel default: 182820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("ERR: 0x%08X, %d", cmd, cmd); 182920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 183020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel }; 183120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 183220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return rval; 183320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 183420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 183520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 183620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Called by the upper tty layer when tty buffers are ready 183720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * to receive data again after a call to throttle. 183820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 183920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void ntty_unthrottle(struct tty_struct *tty) 184020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 184120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 184220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 184320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 184420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("UNTHROTTLE"); 184520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 184620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_dl(tty->index % MAX_PORT, dc); 184720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 1); 184820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 184920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 185020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 185120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 185220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 185320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Called by the upper tty layer when the tty buffers are almost full. 185420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * The driver should stop send more data. 185520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 185620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void ntty_throttle(struct tty_struct *tty) 185720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 185820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 185920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 186020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 186120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("THROTTLE"); 186220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 186320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 0); 186420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 186520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 186620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 186720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Returns number of chars in buffer, called by tty layer */ 186820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic s32 ntty_chars_in_buffer(struct tty_struct *tty) 186920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 187020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 187120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 187223198fda7182969b619613a555f8645fdc3dc334Alan Cox s32 rval = 0; 187320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 187420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!dc || !port)) { 187520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_in_buffer; 187620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 187720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1878e64c026dd09b73faf20707711402fc5ed55a8e70Stefani Seibold rval = kfifo_len(&port->fifo_ul); 187920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 188020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelexit_in_buffer: 188120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return rval; 188220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 188320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1884266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic const struct tty_port_operations noz_tty_port_ops = { 1885266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .activate = ntty_activate, 1886266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .shutdown = ntty_shutdown, 1887266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox}; 1888266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox 188918bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidelstatic const struct tty_operations tty_ops = { 189020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .ioctl = ntty_ioctl, 189120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .open = ntty_open, 189220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .close = ntty_close, 1893266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .hangup = ntty_hangup, 189420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .write = ntty_write, 189520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .write_room = ntty_write_room, 189620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .unthrottle = ntty_unthrottle, 189720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .throttle = ntty_throttle, 189820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .chars_in_buffer = ntty_chars_in_buffer, 189920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .tiocmget = ntty_tiocmget, 190020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .tiocmset = ntty_tiocmset, 19010587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox .get_icount = ntty_tiocgicount, 1902266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .install = ntty_install, 1903266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .cleanup = ntty_cleanup, 190420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 190520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 190620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Module initialization */ 190720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic struct pci_driver nozomi_driver = { 190820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .name = NOZOMI_NAME, 190920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .id_table = nozomi_pci_tbl, 191020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .probe = nozomi_card_init, 191120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .remove = __devexit_p(nozomi_card_exit), 191220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 191320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 191420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic __init int nozomi_init(void) 191520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 191620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ret; 191720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 191820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_INFO "Initializing %s\n", VERSION_STRING); 191920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 192020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver = alloc_tty_driver(NTTY_TTY_MAXMINORS); 192120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!ntty_driver) 192220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return -ENOMEM; 192320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 192420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->owner = THIS_MODULE; 192520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->driver_name = NOZOMI_NAME_TTY; 192620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->name = "noz"; 192720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->major = 0; 192820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->type = TTY_DRIVER_TYPE_SERIAL; 192920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->subtype = SERIAL_TYPE_NORMAL; 193020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 193120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios = tty_std_termios; 193220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | \ 193320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel HUPCL | CLOCAL; 193420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios.c_ispeed = 115200; 193520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios.c_ospeed = 115200; 193620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_set_operations(ntty_driver, &tty_ops); 193720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 193820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = tty_register_driver(ntty_driver); 193920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 194020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_ERR "Nozomi: failed to register ntty driver\n"); 194120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto free_tty; 194220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 194320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 194420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = pci_register_driver(&nozomi_driver); 194520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 194620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_ERR "Nozomi: can't register pci driver\n"); 194720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto unr_tty; 194820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 194920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 195020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 195120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelunr_tty: 195220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_unregister_driver(ntty_driver); 195320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelfree_tty: 195420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel put_tty_driver(ntty_driver); 195520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ret; 195620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 195720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 195820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic __exit void nozomi_exit(void) 195920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 196020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_INFO "Unloading %s\n", DRIVER_DESC); 196120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_unregister_driver(&nozomi_driver); 196220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_unregister_driver(ntty_driver); 196320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel put_tty_driver(ntty_driver); 196420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 196520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 196620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelmodule_init(nozomi_init); 196720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelmodule_exit(nozomi_exit); 196820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 196920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelmodule_param(debug, int, S_IRUGO | S_IWUSR); 197020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 197120fd1e3bea554620d489f3542496639c1babe0b3Frank SeidelMODULE_LICENSE("Dual BSD/GPL"); 197220fd1e3bea554620d489f3542496639c1babe0b3Frank SeidelMODULE_DESCRIPTION(DRIVER_DESC); 1973