120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * nozomi.c -- HSDPA driver Broadband Wireless Data Card - Globe Trotter 320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Written by: Ulf Jakobsson, 5e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel * Jan Åkerfeldt, 620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Stefan Thomasson, 720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Maintained by: Paul Hardwick (p.hardwick@option.com) 920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 1020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Patches: 1120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Locking code changes for Vodafone by Sphere Systems Ltd, 1220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Andrew Bird (ajb@spheresystems.co.uk ) 1320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * & Phil Sanderson 1420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 1520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Source has been ported from an implementation made by Filip Aben @ Option 1620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 1720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -------------------------------------------------------------------------- 1820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 1920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Copyright (c) 2005,2006 Option Wireless Sweden AB 2020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Copyright (c) 2006 Sphere Systems Ltd 2120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Copyright (c) 2006 Option Wireless n/v 2220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * All rights Reserved. 2320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 2420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * This program is free software; you can redistribute it and/or modify 2520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * it under the terms of the GNU General Public License as published by 2620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * the Free Software Foundation; either version 2 of the License, or 2720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * (at your option) any later version. 2820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 2920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * This program is distributed in the hope that it will be useful, 3020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * but WITHOUT ANY WARRANTY; without even the implied warranty of 3120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 3220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * GNU General Public License for more details. 3320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 3420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * You should have received a copy of the GNU General Public License 3520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * along with this program; if not, write to the Free Software 3620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 3720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 3820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -------------------------------------------------------------------------- 3920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 4020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 4120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Enable this to have a lot of debug printouts */ 4220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DEBUG 4320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 4420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/kernel.h> 4520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/module.h> 4620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/pci.h> 4720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/ioport.h> 4820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/tty.h> 4920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/tty_driver.h> 5020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/tty_flip.h> 51d43c36dc6b357fa1806800f18aa30123c747a6d1Alexey Dobriyan#include <linux/sched.h> 5220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/serial.h> 5320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/interrupt.h> 5420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/kmod.h> 5520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/init.h> 5620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/kfifo.h> 5720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/uaccess.h> 585a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 5920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <asm/byteorder.h> 6020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 6120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#include <linux/delay.h> 6220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 6320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 642cae8de7b0464cc4c246517fca10f04593f46a3bMichal Marek#define VERSION_STRING DRIVER_DESC " 2.1d" 6520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 6620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Macros definitions */ 6720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 6820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Default debug printout level */ 6920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_DEBUG_LEVEL 0x00 7020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 7120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define P_BUF_SIZE 128 7220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NFO(_err_flag_, args...) \ 7320fd1e3bea554620d489f3542496639c1babe0b3Frank Seideldo { \ 7420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char tmp[P_BUF_SIZE]; \ 7520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel snprintf(tmp, sizeof(tmp), ##args); \ 7620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(_err_flag_ "[%d] %s(): %s\n", __LINE__, \ 77bf9d89295233ae2ba7b312c78ee5657307b09f4cHarvey Harrison __func__, tmp); \ 7820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} while (0) 7920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 8020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG1(args...) D_(0x01, ##args) 8120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG2(args...) D_(0x02, ##args) 8220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG3(args...) D_(0x04, ##args) 8320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG4(args...) D_(0x08, ##args) 8420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG5(args...) D_(0x10, ##args) 8520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG6(args...) D_(0x20, ##args) 8620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG7(args...) D_(0x40, ##args) 8720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DBG8(args...) D_(0x80, ##args) 8820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 8920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef DEBUG 9020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Do we need this settable at runtime? */ 9120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int debug = NOZOMI_DEBUG_LEVEL; 9220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 93e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel#define D(lvl, args...) do \ 94e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \ 95e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel while (0) 9620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define D_(lvl, args...) D(lvl, ##args) 9720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 9820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* These printouts are always printed */ 9920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 10020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#else 10120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int debug; 10220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define D_(lvl, args...) 10320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 10420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 10520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* TODO: rewrite to optimize macros... */ 10620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 10720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define TMP_BUF_MAX 256 10820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 10920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DUMP(buf__,len__) \ 11020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel do { \ 11120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char tbuf[TMP_BUF_MAX] = {0};\ 11220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (len__ > 1) {\ 11320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel snprintf(tbuf, len__ > TMP_BUF_MAX ? TMP_BUF_MAX : len__, "%s", buf__);\ 11420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (tbuf[len__-2] == '\r') {\ 11520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tbuf[len__-2] = 'r';\ 11620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } \ 11720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("SENDING: '%s' (%d+n)", tbuf, len__);\ 11820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else {\ 11920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("SENDING: '%s' (%d)", tbuf, len__);\ 12020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } \ 12120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} while (0) 12220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 12320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Defines */ 12420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_NAME "nozomi" 12520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_NAME_TTY "nozomi_tty" 12620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DRIVER_DESC "Nozomi driver" 12720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 12820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NTTY_TTY_MAXMINORS 256 12920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NTTY_FIFO_BUFFER_SIZE 8192 13020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Must be power of 2 */ 13220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define FIFO_BUFFER_SIZE_UL 8192 13320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Size of tmp send buffer to card */ 13520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define SEND_BUF_MAX 1024 13620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define RECEIVE_BUF_MAX 4 13720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 13920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define R_IIR 0x0000 /* Interrupt Identity Register */ 14020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define R_FCR 0x0000 /* Flow Control Register */ 14120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define R_IER 0x0004 /* Interrupt Enable Register */ 14220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CONFIG_MAGIC 0xEFEFFEFE 14420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define TOGGLE_VALID 0x0000 14520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Definition of interrupt tokens */ 14720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_DL1 0x0001 14820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_UL1 0x0002 14920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_DL2 0x0004 15020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_UL2 0x0008 15120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_DL1 0x0010 15220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_DL2 0x0020 15320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_UL 0x0040 15420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP1_DL 0x0080 15520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP1_UL 0x0100 15620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP2_DL 0x0200 15720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define APP2_UL 0x0400 15820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DL 0x0800 15920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_UL 0x1000 16020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define RESET 0x8000 16120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 16220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_DL (MDM_DL1 | MDM_DL2) 16320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MDM_UL (MDM_UL1 | MDM_UL2) 16420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define DIAG_DL (DIAG_DL1 | DIAG_DL2) 16520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 16620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* modem signal definition */ 16720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DSR 0x0001 16820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DCD 0x0002 16920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_RI 0x0004 17020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_CTS 0x0008 17120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 17220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_DTR 0x0001 17320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define CTRL_RTS 0x0002 17420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 17520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define MAX_PORT 4 17620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_MAX_PORTS 5 17720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#define NOZOMI_MAX_CARDS (NTTY_TTY_MAXMINORS / MAX_PORT) 17820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 17920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Type definitions */ 18020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 18120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 18220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * There are two types of nozomi cards, 18320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * one with 2048 memory and with 8192 memory 18420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 18520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum card_type { 18620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel F32_2 = 2048, /* 512 bytes downlink + uplink * 2 -> 2048 */ 18720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel F32_8 = 8192, /* 3072 bytes downl. + 1024 bytes uplink * 2 -> 8192 */ 18820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 18920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 190661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel/* Initialization states a card can be in */ 191661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidelenum card_state { 192661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_UKNOWN = 0, 193661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_ENABLED = 1, /* pci device enabled */ 194661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_ALLOCATED = 2, /* config setup done */ 195661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel NOZOMI_STATE_READY = 3, /* flowcontrols received */ 196661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel}; 197661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 19820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Two different toggle channels exist */ 19920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum channel_type { 20020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CH_A = 0, 20120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CH_B = 1, 20220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 20320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 20420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Port definition for the card regarding flow control */ 20520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum ctrl_port_type { 20620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_CMD = 0, 20720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_MDM = 1, 20820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_DIAG = 2, 20920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_APP1 = 3, 21020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_APP2 = 4, 21120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel CTRL_ERROR = -1, 21220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 21320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 21420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Ports that the nozomi has */ 21520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelenum port_type { 21620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_MDM = 0, 21720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_DIAG = 1, 21820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_APP1 = 2, 21920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_APP2 = 3, 22020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_CTRL = 4, 22120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel PORT_ERROR = -1, 22220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 22320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 22420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef __BIG_ENDIAN 22520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Big endian */ 22620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 22720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct toggles { 228e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int enabled:5; /* 22920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Toggle fields are valid if enabled is 0, 23020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * else A-channels must always be used. 23120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 232e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int diag_dl:1; 233e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_dl:1; 234e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_ul:1; 23520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 23620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 23720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Configuration table to read at startup of card */ 23820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Is for now only needed during initialization phase */ 23920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct config_table { 24020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 signature; 24120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 product_information; 24220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 version; 24320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad3[3]; 24420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct toggles toggle; 24520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad1[4]; 24620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len1; /* 24720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * If this is 64, it can hold 24820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 60 bytes + 4 that is length field 24920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 25020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_start; 25120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 25220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len1; 25320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len2; /* 25420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * If this is 64, it can hold 25520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 60 bytes + 4 that is length field 25620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 25720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app1_len; 25820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 25920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len2; 26020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_ctrl_len; 26120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app2_len; 26220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad2[16]; 26320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len1; 26420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_start; 26520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_diag_len; 26620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len2; 26720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app1_len; 26820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app2_len; 26920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_ctrl_len; 27020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 27120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 27220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control downlink flags */ 27320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_dl { 27420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 275e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserved:4; 276e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int CTS:1; 277e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RI:1; 278e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DCD:1; 279e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DSR:1; 28020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 28120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 28220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control uplink flags */ 28320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_ul { 28420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 285e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserved:6; 286e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RTS:1; 287e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DTR:1; 28820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 28920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 29020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#else 29120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Little endian */ 29220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 29320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This represents the toggle information */ 29420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct toggles { 295e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_ul:1; 296e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int mdm_dl:1; 297e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int diag_dl:1; 298e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int enabled:5; /* 29920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Toggle fields are valid if enabled is 0, 30020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * else A-channels must always be used. 30120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 30220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 30320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 30420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Configuration table to read at startup of card */ 30520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct config_table { 30620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 signature; 30720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 version; 30820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 product_information; 30920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct toggles toggle; 31020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad1[7]; 31120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_start; 31220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len1; /* 31320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * If this is 64, it can hold 31420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * 60 bytes + 4 that is length field 31520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 31620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_mdm_len2; 31720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len1; 31820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_diag_len2; 31920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app1_len; 32020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_app2_len; 32120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 dl_ctrl_len; 32220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 pad2[16]; 32320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_start; 32420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len2; 32520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_mdm_len1; 32620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_diag_len; 32720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app1_len; 32820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_app2_len; 32920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 ul_ctrl_len; 33020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 33120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 33220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control downlink flags */ 33320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_dl { 334e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DSR:1; 335e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DCD:1; 336e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RI:1; 337e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int CTS:1; 338e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserverd:4; 33920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 34020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 34120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 34220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This stores all control uplink flags */ 34320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct ctrl_ul { 344e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int DTR:1; 345e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int RTS:1; 346e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel unsigned int reserved:6; 34720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 port; 34820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 34920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 35020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 35120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This holds all information that is needed regarding a port */ 35220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct port { 35333dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_port port; 35420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 update_flow_control; 35520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_ul ctrl_ul; 35620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_dl ctrl_dl; 35745465487897a1c6d508b14b904dc5777f7ec7e04Stefani Seibold struct kfifo fifo_ul; 35820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *dl_addr[2]; 35920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 dl_size[2]; 36020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 toggle_dl; 36120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *ul_addr[2]; 36220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 ul_size[2]; 36320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 toggle_ul; 36420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 token_dl; 36520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 36620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel wait_queue_head_t tty_wait; 36720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct async_icount tty_icount; 368266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox 369266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct nozomi *dc; 37020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 37120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 37220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Private data one for each card in the system */ 37320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct nozomi { 37420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *base_addr; 37520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flip; 37620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 37720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Pointers to registers */ 37820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *reg_iir; 37920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *reg_fcr; 38020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *reg_ier; 38120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 38220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 last_ier; 38320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enum card_type card_type; 38420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct config_table config_table; /* Configuration table */ 38520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct pci_dev *pdev; 38620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port port[NOZOMI_MAX_PORTS]; 38720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 *send_buf; 38820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 38920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spinlock_t spin_mutex; /* secures access to registers and tty */ 39020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 39120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int index_start; 392661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel enum card_state state; 39320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 open_ttys; 39420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 39520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 39620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* This is a data packet that is read or written to/from card */ 39720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstruct buffer { 39820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size; /* size is the length of the data buffer */ 39920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 *data; 40020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} __attribute__ ((packed)); 40120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 40220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Global variables */ 40318bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidelstatic const struct pci_device_id nozomi_pci_tbl[] __devinitconst = { 404b2a3dbc3ed401828c4de0f08d08d96d0f5ea5b0bAlan Cox {PCI_DEVICE(0x1931, 0x000c)}, /* Nozomi HSDPA */ 40520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel {}, 40620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 40720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 40820fd1e3bea554620d489f3542496639c1babe0b3Frank SeidelMODULE_DEVICE_TABLE(pci, nozomi_pci_tbl); 40920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 41020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic struct nozomi *ndevs[NOZOMI_MAX_CARDS]; 41120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic struct tty_driver *ntty_driver; 41220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 413266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic const struct tty_port_operations noz_tty_port_ops; 414266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox 41520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 41620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * find card by tty_index 41720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 41820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic inline struct nozomi *get_dc_by_tty(const struct tty_struct *tty) 41920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 42020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return tty ? ndevs[tty->index / MAX_PORT] : NULL; 42120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 42220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 42320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic inline struct port *get_port_by_tty(const struct tty_struct *tty) 42420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 42520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *ndev = get_dc_by_tty(tty); 42620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ndev ? &ndev->port[tty->index % MAX_PORT] : NULL; 42720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 42820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 42920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 43020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * TODO: 43120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -Optimize 43220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -Rewrite cleaner 43320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 43420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 43520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void read_mem32(u32 *buf, const void __iomem *mem_addr_start, 43620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size_bytes) 43720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 43820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 i = 0; 439782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro const u32 __iomem *ptr = mem_addr_start; 44020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 *buf16; 44120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 44220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!ptr || !buf)) 44320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto out; 44420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 44520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* shortcut for extremely often used cases */ 44620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (size_bytes) { 44720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 2: /* 2 bytes */ 44820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel buf16 = (u16 *) buf; 449782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro *buf16 = __le16_to_cpu(readw(ptr)); 45020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto out; 45120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 45220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 4: /* 4 bytes */ 453782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro *(buf) = __le32_to_cpu(readl(ptr)); 45420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto out; 45520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 45620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 45720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 45820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel while (i < size_bytes) { 45920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (size_bytes - i == 2) { 46020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Handle 2 bytes in the end */ 46120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel buf16 = (u16 *) buf; 462782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro *(buf16) = __le16_to_cpu(readw(ptr)); 46320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i += 2; 46420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 46520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Read 4 bytes */ 466782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro *(buf) = __le32_to_cpu(readl(ptr)); 46720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i += 4; 46820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 46920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel buf++; 47020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ptr++; 47120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 47220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelout: 47320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return; 47420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 47520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 47620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 47720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * TODO: 47820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -Optimize 47920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * -Rewrite cleaner 48020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 48171e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardtstatic u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf, 48220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size_bytes) 48320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 48420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 i = 0; 485782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro u32 __iomem *ptr = mem_addr_start; 48671e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const u16 *buf16; 48720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 48820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!ptr || !buf)) 48920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 49020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 49120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* shortcut for extremely often used cases */ 49220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (size_bytes) { 49320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 2: /* 2 bytes */ 49471e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt buf16 = (const u16 *)buf; 495782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro writew(__cpu_to_le16(*buf16), ptr); 49620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 2; 49720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 49820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 1: /* 49920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * also needs to write 4 bytes in this case 50020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * so falling through.. 50120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 50220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case 4: /* 4 bytes */ 503782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro writel(__cpu_to_le32(*buf), ptr); 50420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 4; 50520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 50620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 50720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 50820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel while (i < size_bytes) { 50920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (size_bytes - i == 2) { 51020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 2 bytes */ 51171e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt buf16 = (const u16 *)buf; 512782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro writew(__cpu_to_le16(*buf16), ptr); 51320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i += 2; 51420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 51520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 4 bytes */ 516782a6de47b97d5c5f16c84f7868606fa25781fecAl Viro writel(__cpu_to_le32(*buf), ptr); 51720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i += 4; 51820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 51920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel buf++; 52020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ptr++; 52120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 52220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return i; 52320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 52420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 52520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Setup pointers to different channels and also setup buffer sizes. */ 52620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void setup_memory(struct nozomi *dc) 52720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 52820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *offset = dc->base_addr + dc->config_table.dl_start; 52920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* The length reported is including the length field of 4 bytes, 53020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * hence subtract with 4. 53120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 53220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel const u16 buff_offset = 4; 53320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 53420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Modem port dl configuration */ 53520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].dl_addr[CH_A] = offset; 53620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].dl_addr[CH_B] = 53720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_mdm_len1); 53820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].dl_size[CH_A] = 53920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_mdm_len1 - buff_offset; 54020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].dl_size[CH_B] = 54120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_mdm_len2 - buff_offset; 54220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 54320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Diag port dl configuration */ 54420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].dl_addr[CH_A] = 54520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_mdm_len2); 54620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].dl_size[CH_A] = 54720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_diag_len1 - buff_offset; 54820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].dl_addr[CH_B] = 54920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_diag_len1); 55020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].dl_size[CH_B] = 55120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_diag_len2 - buff_offset; 55220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 55320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* App1 port dl configuration */ 55420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].dl_addr[CH_A] = 55520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_diag_len2); 55620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].dl_size[CH_A] = 55720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_app1_len - buff_offset; 55820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 55920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* App2 port dl configuration */ 56020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].dl_addr[CH_A] = 56120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_app1_len); 56220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].dl_size[CH_A] = 56320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_app2_len - buff_offset; 56420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 56520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Ctrl dl configuration */ 56620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_CTRL].dl_addr[CH_A] = 56720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.dl_app2_len); 56820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_CTRL].dl_size[CH_A] = 56920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_ctrl_len - buff_offset; 57020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 57120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel offset = dc->base_addr + dc->config_table.ul_start; 57220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 57320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Modem Port ul configuration */ 57420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].ul_addr[CH_A] = offset; 57520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].ul_size[CH_A] = 57620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_mdm_len1 - buff_offset; 57720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].ul_addr[CH_B] = 57820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_mdm_len1); 57920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].ul_size[CH_B] = 58020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_mdm_len2 - buff_offset; 58120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 58220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Diag port ul configuration */ 58320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].ul_addr[CH_A] = 58420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_mdm_len2); 58520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].ul_size[CH_A] = 58620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_diag_len - buff_offset; 58720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 58820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* App1 port ul configuration */ 58920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].ul_addr[CH_A] = 59020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_diag_len); 59120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].ul_size[CH_A] = 59220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_app1_len - buff_offset; 59320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 59420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* App2 port ul configuration */ 59520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].ul_addr[CH_A] = 59620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_app1_len); 59720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].ul_size[CH_A] = 59820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_app2_len - buff_offset; 59920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 60020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Ctrl ul configuration */ 60120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_CTRL].ul_addr[CH_A] = 60220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (offset += dc->config_table.ul_app2_len); 60320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_CTRL].ul_size[CH_A] = 60420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_ctrl_len - buff_offset; 60520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 60620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 60720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Dump config table under initalization phase */ 60820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef DEBUG 60920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void dump_table(const struct nozomi *dc) 61020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 61120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("signature: 0x%08X", dc->config_table.signature); 61220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("version: 0x%04X", dc->config_table.version); 61320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("product_information: 0x%04X", \ 61420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.product_information); 61520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("toggle enabled: %d", dc->config_table.toggle.enabled); 61620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("toggle up_mdm: %d", dc->config_table.toggle.mdm_ul); 61720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("toggle dl_mdm: %d", dc->config_table.toggle.mdm_dl); 61820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("toggle dl_dbg: %d", dc->config_table.toggle.diag_dl); 61920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 62020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_start: 0x%04X", dc->config_table.dl_start); 62120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_mdm_len0: 0x%04X, %d", dc->config_table.dl_mdm_len1, 62220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_mdm_len1); 62320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_mdm_len1: 0x%04X, %d", dc->config_table.dl_mdm_len2, 62420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_mdm_len2); 62520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_diag_len0: 0x%04X, %d", dc->config_table.dl_diag_len1, 62620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_diag_len1); 62720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_diag_len1: 0x%04X, %d", dc->config_table.dl_diag_len2, 62820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_diag_len2); 62920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_app1_len: 0x%04X, %d", dc->config_table.dl_app1_len, 63020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_app1_len); 63120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_app2_len: 0x%04X, %d", dc->config_table.dl_app2_len, 63220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_app2_len); 63320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("dl_ctrl_len: 0x%04X, %d", dc->config_table.dl_ctrl_len, 63420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.dl_ctrl_len); 63520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_start: 0x%04X, %d", dc->config_table.ul_start, 63620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_start); 63720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_mdm_len[0]: 0x%04X, %d", dc->config_table.ul_mdm_len1, 63820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_mdm_len1); 63920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_mdm_len[1]: 0x%04X, %d", dc->config_table.ul_mdm_len2, 64020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_mdm_len2); 64120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_diag_len: 0x%04X, %d", dc->config_table.ul_diag_len, 64220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_diag_len); 64320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_app1_len: 0x%04X, %d", dc->config_table.ul_app1_len, 64420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_app1_len); 64520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_app2_len: 0x%04X, %d", dc->config_table.ul_app2_len, 64620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_app2_len); 64720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG3("ul_ctrl_len: 0x%04X, %d", dc->config_table.ul_ctrl_len, 64820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.ul_ctrl_len); 64920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 65020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#else 651e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidelstatic inline void dump_table(const struct nozomi *dc) { } 65220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 65320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 65420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 65520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Read configuration table from card under intalization phase 65620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Returns 1 if ok, else 0 65720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 65820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int nozomi_read_config_table(struct nozomi *dc) 65920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 66020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_mem32((u32 *) &dc->config_table, dc->base_addr + 0, 66120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel sizeof(struct config_table)); 66220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 66320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (dc->config_table.signature != CONFIG_MAGIC) { 66420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "ConfigTable Bad! 0x%08X != 0x%08X\n", 66520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.signature, CONFIG_MAGIC); 66620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 66720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 66820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 66920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if ((dc->config_table.version == 0) 67020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel || (dc->config_table.toggle.enabled == TOGGLE_VALID)) { 67120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 67220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Second phase, configuring card"); 67320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 67420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel setup_memory(dc); 67520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 67620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].toggle_ul = dc->config_table.toggle.mdm_ul; 67720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].toggle_dl = dc->config_table.toggle.mdm_dl; 67820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].toggle_dl = dc->config_table.toggle.diag_dl; 67920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("toggle ports: MDM UL:%d MDM DL:%d, DIAG DL:%d", 68020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].toggle_ul, 68120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].toggle_dl, dc->port[PORT_DIAG].toggle_dl); 68220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 68320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dump_table(dc); 68420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 68520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = PORT_MDM; i < MAX_PORT; i++) { 68620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel memset(&dc->port[i].ctrl_dl, 0, sizeof(struct ctrl_dl)); 68720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel memset(&dc->port[i].ctrl_ul, 0, sizeof(struct ctrl_ul)); 68820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 68920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 69020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Enable control channel */ 69120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | CTRL_DL; 69220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 69320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 694661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->state = NOZOMI_STATE_ALLOCATED; 69520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_info(&dc->pdev->dev, "Initialization OK!\n"); 69620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 69720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 69820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 69920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if ((dc->config_table.version > 0) 70020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel && (dc->config_table.toggle.enabled != TOGGLE_VALID)) { 70120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 offset = 0; 70220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("First phase: pushing upload buffers, clearing download"); 70320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 70420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_info(&dc->pdev->dev, "Version of card: %d\n", 70520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->config_table.version); 70620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 70720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Here we should disable all I/O over F32. */ 70820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel setup_memory(dc); 70920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 71020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 71120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * We should send ALL channel pair tokens back along 71220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * with reset token 71320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 71420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 71520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* push upload modem buffers */ 71620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_MDM].ul_addr[CH_A], 71720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (u32 *) &offset, 4); 71820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_MDM].ul_addr[CH_B], 71920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (u32 *) &offset, 4); 72020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 72120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL | DIAG_DL | MDM_DL, dc->reg_fcr); 72220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 72320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("First phase done"); 72420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 72520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 72620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 72720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 72820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 72920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Enable uplink interrupts */ 73020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void enable_transmit_ul(enum port_type port, struct nozomi *dc) 73120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 73271e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL}; 73320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 73420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 73520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier |= mask[port]; 73620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 73720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 73820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 73920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 74020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 74120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 74220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Disable uplink interrupts */ 74320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void disable_transmit_ul(enum port_type port, struct nozomi *dc) 74420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 74571e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = 74671e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL}; 74720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 74820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 74920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= mask[port]; 75020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 75120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 75220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 75320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 75420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 75520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 75620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Enable downlink interrupts */ 75720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void enable_transmit_dl(enum port_type port, struct nozomi *dc) 75820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 75971e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL}; 76020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 76120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 76220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier |= mask[port]; 76320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 76420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 76520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 76620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 76720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 76820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 76920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Disable downlink interrupts */ 77020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void disable_transmit_dl(enum port_type port, struct nozomi *dc) 77120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 77271e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt static const u16 mask[] = 77371e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL}; 77420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 77520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port < NOZOMI_MAX_PORTS) { 77620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= mask[port]; 77720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 77820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 77920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Called with wrong port?\n"); 78020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 78120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 78220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 78320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 78420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - send buffer to card and ack. 78520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - don't ack, don't send buffer to card. 78620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 78733dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Coxstatic int send_data(enum port_type index, struct nozomi *dc) 78820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 78920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size = 0; 79033dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct port *port = &dc->port[index]; 79118bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const u8 toggle = port->toggle_ul; 79220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *addr = port->ul_addr[toggle]; 79318bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const u32 ul_size = port->ul_size[toggle]; 79433dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_struct *tty = tty_port_tty_get(&port->port); 79520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 79620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Get data from tty and place in buf for now */ 7977acd72eb85f1c7a15e8b5eb554994949241737f1Stefani Seibold size = kfifo_out(&port->fifo_ul, dc->send_buf, 79820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ul_size < SEND_BUF_MAX ? ul_size : SEND_BUF_MAX); 79920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 80020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (size == 0) { 80120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG4("No more data to send, disable link:"); 80233dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 80320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 80420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 80520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 80620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* DUMP(buf, size); */ 80720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 80820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Write length + data */ 80920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(addr, (u32 *) &size, 4); 81020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(addr + 4, (u32 *) dc->send_buf, size); 81120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 81220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (tty) 81320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_wakeup(tty); 81420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 81533dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 81620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 81720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 81820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 81920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* If all data has been read, return 1, else 0 */ 82020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int receive_data(enum port_type index, struct nozomi *dc) 82120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 82220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 buf[RECEIVE_BUF_MAX] = { 0 }; 82320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int size; 82420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 offset = 4; 82520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = &dc->port[index]; 82620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *addr = port->dl_addr[port->toggle_dl]; 82733dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_struct *tty = tty_port_tty_get(&port->port); 8289237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby int i, ret; 82920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 83020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!tty)) { 83120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("tty not open for port: %d?", index); 83220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 83320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 83420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 83520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_mem32((u32 *) &size, addr, 4); 83620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* DBG1( "%d bytes port: %d", size, index); */ 83720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 83820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (test_bit(TTY_THROTTLED, &tty->flags)) { 83920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("No room in tty, don't read data, don't ack interrupt, " 84020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "disable interrupt"); 84120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 84220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* disable interrupt in downlink... */ 84320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel disable_transmit_dl(index, dc); 8449237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby ret = 0; 8459237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby goto put; 84620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 84720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 84820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(size == 0)) { 84920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "size == 0?\n"); 8509237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby ret = 1; 8519237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby goto put; 85220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 85320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 85420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel while (size > 0) { 85520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_mem32((u32 *) buf, addr + offset, RECEIVE_BUF_MAX); 85620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 85720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (size == 1) { 85820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_insert_flip_char(tty, buf[0], TTY_NORMAL); 85920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel size = 0; 86020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (size < RECEIVE_BUF_MAX) { 86120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel size -= tty_insert_flip_string(tty, (char *) buf, size); 86220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 86320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel i = tty_insert_flip_string(tty, \ 86420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (char *) buf, RECEIVE_BUF_MAX); 86520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel size -= i; 86620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel offset += i; 86720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 86820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 86920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 87020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_bit(index, &dc->flip); 8719237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby ret = 1; 8729237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slabyput: 87333dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 8749237a81a1468d0aca1cc4e244bba2362d6f81b35Jiri Slaby return ret; 87520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 87620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 87720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Debug for interrupts */ 87820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#ifdef DEBUG 87920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic char *interrupt2str(u16 interrupt) 88020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 88120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel static char buf[TMP_BUF_MAX]; 88220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char *p = buf; 88320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 88420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_DL1 ? p += snprintf(p, TMP_BUF_MAX, "MDM_DL1 ") : NULL; 88520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 88620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "MDM_DL2 ") : NULL; 88720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 88820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_UL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 88920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "MDM_UL1 ") : NULL; 89020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & MDM_UL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "MDM_UL2 ") : NULL; 89220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 89320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & DIAG_DL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "DIAG_DL1 ") : NULL; 89520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & DIAG_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "DIAG_DL2 ") : NULL; 89720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 89820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & DIAG_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 89920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "DIAG_UL ") : NULL; 90020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 90120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP1_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP1_DL ") : NULL; 90320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP2_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP2_DL ") : NULL; 90520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 90620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP1_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP1_UL ") : NULL; 90820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & APP2_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 90920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "APP2_UL ") : NULL; 91020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 91120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & CTRL_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 91220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "CTRL_DL ") : NULL; 91320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & CTRL_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 91420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "CTRL_UL ") : NULL; 91520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 91620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel interrupt & RESET ? p += snprintf(p, TMP_BUF_MAX - (p - buf), 91720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "RESET ") : NULL; 91820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 91920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return buf; 92020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 92120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel#endif 92220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 92320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 92420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Receive flow control 92520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - If ok, else 0 92620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 92720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int receive_flow_control(struct nozomi *dc) 92820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 92920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enum port_type port = PORT_MDM; 93020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_dl ctrl_dl; 93120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_dl old_ctrl; 93220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 enable_ier = 0; 93320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 93420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_mem32((u32 *) &ctrl_dl, dc->port[PORT_CTRL].dl_addr[CH_A], 2); 93520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 93620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (ctrl_dl.port) { 93720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_CMD: 93820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("The Base Band sends this value as a response to a " 93920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "request for IMSI detach sent over the control " 94020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "channel uplink (see section 7.6.1)."); 94120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 94220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_MDM: 94320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_MDM; 94420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = MDM_DL; 94520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 94620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_DIAG: 94720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_DIAG; 94820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = DIAG_DL; 94920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 95020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_APP1: 95120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_APP1; 95220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = APP1_DL; 95320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 95420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case CTRL_APP2: 95520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port = PORT_APP2; 95620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier = APP2_DL; 957661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel if (dc->state == NOZOMI_STATE_ALLOCATED) { 958661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel /* 959661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel * After card initialization the flow control 960661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel * received for APP2 is always the last 961661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel */ 962661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->state = NOZOMI_STATE_READY; 963661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dev_info(&dc->pdev->dev, "Device READY!\n"); 964661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel } 96520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 96620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel default: 96720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 96820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "ERROR: flow control received for non-existing port\n"); 96920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 97020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel }; 97120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 97220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("0x%04X->0x%04X", *((u16 *)&dc->port[port].ctrl_dl), 97320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *((u16 *)&ctrl_dl)); 97420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 97520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel old_ctrl = dc->port[port].ctrl_dl; 97620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].ctrl_dl = ctrl_dl; 97720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 97820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.CTS == 1 && ctrl_dl.CTS == 0) { 97920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Disable interrupt (0x%04X) on port: %d", 98020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier, port); 98120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel disable_transmit_ul(port, dc); 98220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 98320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (old_ctrl.CTS == 0 && ctrl_dl.CTS == 1) { 98420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 985e64c026dd09b73faf20707711402fc5ed55a8e70Stefani Seibold if (kfifo_len(&dc->port[port].fifo_ul)) { 98620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Enable interrupt (0x%04X) on port: %d", 98720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_ier, port); 98820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("Data in buffer [%d], enable transmit! ", 989e64c026dd09b73faf20707711402fc5ed55a8e70Stefani Seibold kfifo_len(&dc->port[port].fifo_ul)); 99020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(port, dc); 99120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 99220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("No data in buffer..."); 99320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 99420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 99520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 99620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (*(u16 *)&old_ctrl == *(u16 *)&ctrl_dl) { 99720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1(" No change in mctrl"); 99820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 99920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 100020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Update statistics */ 100120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.CTS != ctrl_dl.CTS) 100220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.cts++; 100320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.DSR != ctrl_dl.DSR) 100420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.dsr++; 100520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.RI != ctrl_dl.RI) 100620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.rng++; 100720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (old_ctrl.DCD != ctrl_dl.DCD) 100820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.dcd++; 100920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 101020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel wake_up_interruptible(&dc->port[port].tty_wait); 101120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 101220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("port: %d DCD(%d), CTS(%d), RI(%d), DSR(%d)", 101320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port, 101420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.dcd, dc->port[port].tty_icount.cts, 101520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[port].tty_icount.rng, dc->port[port].tty_icount.dsr); 101620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 101720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 101820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 101920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 102020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic enum ctrl_port_type port2ctrl(enum port_type port, 102120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel const struct nozomi *dc) 102220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 102320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (port) { 102420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_MDM: 102520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_MDM; 102620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_DIAG: 102720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_DIAG; 102820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_APP1: 102920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_APP1; 103020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case PORT_APP2: 103120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_APP2; 103220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel default: 103320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 103420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "ERROR: send flow control " \ 103520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "received for non-existing port\n"); 103620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel }; 103720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return CTRL_ERROR; 103820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 103920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 104020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 104120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Send flow control, can only update one channel at a time 104220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - If we have updated all flow control 104320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - If we need to update more flow control, ack current enable more 104420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 104520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int send_flow_control(struct nozomi *dc) 104620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 104720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 i, more_flow_control_to_be_updated = 0; 104820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 *ctrl; 104920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 105020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = PORT_MDM; i < MAX_PORT; i++) { 105120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (dc->port[i].update_flow_control) { 105220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (more_flow_control_to_be_updated) { 105320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* We have more flow control to be updated */ 105420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 105520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 105620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[i].ctrl_ul.port = port2ctrl(i, dc); 105720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl = (u16 *)&dc->port[i].ctrl_ul; 105820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_CTRL].ul_addr[0], \ 105920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (u32 *) ctrl, 2); 106020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[i].update_flow_control = 0; 106120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel more_flow_control_to_be_updated = 1; 106220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 106320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 106420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 106520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 106620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 106720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 1068e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidel * Handle downlink data, ports that are handled are modem and diagnostics 106920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - ok 107020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - toggle fields are out of sync 107120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 107220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int handle_data_dl(struct nozomi *dc, enum port_type port, u8 *toggle, 107320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 read_iir, u16 mask1, u16 mask2) 107420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 107520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (*toggle == 0 && read_iir & mask1) { 107620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 107720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask1, dc->reg_fcr); 107820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 107920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 108020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 108120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & mask2) { 108220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 108320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask2, dc->reg_fcr); 108420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 108520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 108620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 108720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (*toggle == 1 && read_iir & mask2) { 108820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 108920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask2, dc->reg_fcr); 109020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 109120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 109220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 109320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & mask1) { 109420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(port, dc)) { 109520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(mask1, dc->reg_fcr); 109620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !(*toggle); 109720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 109820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 109920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 110020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "port out of sync!, toggle:%d\n", 110120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle); 110220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 110320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 110420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 110520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 110620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 110720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 110820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Handle uplink data, this is currently for the modem port 110920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 1 - ok 111020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Return 0 - toggle field are out of sync 111120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 111220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int handle_data_ul(struct nozomi *dc, enum port_type port, u16 read_iir) 111320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 111420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u8 *toggle = &(dc->port[port].toggle_ul); 111520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 111620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (*toggle == 0 && read_iir & MDM_UL1) { 111720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 111820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 111920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 112020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL1, dc->reg_fcr); 112120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 112220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 112320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 112420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 112520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 112620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_UL2) { 112720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 112820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 112920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 113020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL2, dc->reg_fcr); 113120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 113220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 113320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 113420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 113520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 113620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 113720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else if (*toggle == 1 && read_iir & MDM_UL2) { 113820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 113920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 114020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 114120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL2, dc->reg_fcr); 114220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 114320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 114420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 114520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 114620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 114720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_UL1) { 114820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~MDM_UL; 114920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 115020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(port, dc)) { 115120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(MDM_UL1, dc->reg_fcr); 115220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | MDM_UL; 115320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 115420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *toggle = !*toggle; 115520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 115620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 115720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 115820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(read_iir & MDM_UL, dc->reg_fcr); 115920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "port out of sync!\n"); 116020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 116120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 116220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 1; 116320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 116420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 116520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic irqreturn_t interrupt_handler(int irq, void *dev_id) 116620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 116720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = dev_id; 116820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int a; 116920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u16 read_iir; 117020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 117120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc) 117220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return IRQ_NONE; 117320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 117420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock(&dc->spin_mutex); 117520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_iir = readw(dc->reg_iir); 117620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 117720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Card removed */ 117820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir == (u16)-1) 117920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto none; 118020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* 118120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Just handle interrupt enabled in IER 118220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * (by masking with dc->last_ier) 118320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 118420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel read_iir &= dc->last_ier; 118520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 118620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir == 0) 118720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto none; 118820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 118920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 119020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG4("%s irq:0x%04X, prev:0x%04X", interrupt2str(read_iir), read_iir, 119120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier); 119220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 119320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & RESET) { 119420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!nozomi_read_config_table(dc))) { 119520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0x0; 119620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 119720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "Could not read status from " 119820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "card, we should disable interface\n"); 119920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 120020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(RESET, dc->reg_fcr); 120120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 120220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* No more useful info if this was the reset interrupt. */ 120320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 120420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 120520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & CTRL_UL) { 120620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("CTRL_UL"); 120720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~CTRL_UL; 120820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 120920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_flow_control(dc)) { 121020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(CTRL_UL, dc->reg_fcr); 121120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | CTRL_UL; 121220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 121320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 121420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 121520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & CTRL_DL) { 121620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel receive_flow_control(dc); 121720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(CTRL_DL, dc->reg_fcr); 121820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 121920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_DL) { 122020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!handle_data_dl(dc, PORT_MDM, 122120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel &(dc->port[PORT_MDM].toggle_dl), read_iir, 122220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel MDM_DL1, MDM_DL2)) { 122320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "MDM_DL out of sync!\n"); 122420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 122520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 122620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 122720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & MDM_UL) { 122820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!handle_data_ul(dc, PORT_MDM, read_iir)) { 122920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "MDM_UL out of sync!\n"); 123020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 123120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 123220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 123320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & DIAG_DL) { 123420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!handle_data_dl(dc, PORT_DIAG, 123520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel &(dc->port[PORT_DIAG].toggle_dl), read_iir, 123620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DIAG_DL1, DIAG_DL2)) { 123720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, "DIAG_DL out of sync!\n"); 123820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_handler; 123920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 124020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 124120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & DIAG_UL) { 124220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~DIAG_UL; 124320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 124420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(PORT_DIAG, dc)) { 124520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(DIAG_UL, dc->reg_fcr); 124620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | DIAG_UL; 124720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 124820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 124920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 125020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP1_DL) { 125120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(PORT_APP1, dc)) 125220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP1_DL, dc->reg_fcr); 125320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 125420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP1_UL) { 125520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~APP1_UL; 125620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 125720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(PORT_APP1, dc)) { 125820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP1_UL, dc->reg_fcr); 125920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | APP1_UL; 126020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 126120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 126220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 126320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP2_DL) { 126420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (receive_data(PORT_APP2, dc)) 126520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP2_DL, dc->reg_fcr); 126620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 126720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (read_iir & APP2_UL) { 126820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier &= ~APP2_UL; 126920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 127020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (send_data(PORT_APP2, dc)) { 127120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(APP2_UL, dc->reg_fcr); 127220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = dc->last_ier | APP2_UL; 127320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 127420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 127520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 127620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 127720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelexit_handler: 127820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock(&dc->spin_mutex); 127933dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox for (a = 0; a < NOZOMI_MAX_PORTS; a++) { 128033dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_struct *tty; 128133dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox if (test_and_clear_bit(a, &dc->flip)) { 128233dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty = tty_port_tty_get(&dc->port[a].port); 128333dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox if (tty) 128433dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_flip_buffer_push(tty); 128533dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 128633dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox } 128733dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox } 128820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return IRQ_HANDLED; 128920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelnone: 129020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock(&dc->spin_mutex); 129120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return IRQ_NONE; 129220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 129320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 129420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void nozomi_get_card_type(struct nozomi *dc) 129520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 129620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 129720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel u32 size = 0; 129820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 129920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < 6; i++) 130020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel size += pci_resource_len(dc->pdev, i); 130120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 130220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Assume card type F32_8 if no match */ 130320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->card_type = size == 2048 ? F32_2 : F32_8; 130420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 130520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_info(&dc->pdev->dev, "Card type is: %d\n", dc->card_type); 130620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 130720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 130820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void nozomi_setup_private_data(struct nozomi *dc) 130920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 131020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel void __iomem *offset = dc->base_addr + dc->card_type / 2; 131120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int i; 131220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 131320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->reg_fcr = (void __iomem *)(offset + R_FCR); 131420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->reg_iir = (void __iomem *)(offset + R_IIR); 131520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->reg_ier = (void __iomem *)(offset + R_IER); 131620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0; 131720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->flip = 0; 131820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 131920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_MDM].token_dl = MDM_DL; 132020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_DIAG].token_dl = DIAG_DL; 132120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP1].token_dl = APP1_DL; 132220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->port[PORT_APP2].token_dl = APP2_DL; 132320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 132420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < MAX_PORT; i++) 132520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel init_waitqueue_head(&dc->port[i].tty_wait); 132620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 132720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 132820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic ssize_t card_type_show(struct device *dev, struct device_attribute *attr, 132920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char *buf) 133020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 133171e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); 133220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 133320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return sprintf(buf, "%d\n", dc->card_type); 133420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 1335e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidelstatic DEVICE_ATTR(card_type, S_IRUGO, card_type_show, NULL); 133620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 133720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr, 133820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel char *buf) 133920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 134071e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); 134120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 134220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return sprintf(buf, "%u\n", dc->open_ttys); 134320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 1344e9ed537a3ab0b066eaa4d042c0547d7034f3181bFrank Seidelstatic DEVICE_ATTR(open_ttys, S_IRUGO, open_ttys_show, NULL); 134520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 134620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void make_sysfs_files(struct nozomi *dc) 134720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 134820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (device_create_file(&dc->pdev->dev, &dev_attr_card_type)) 134920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 135020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "Could not create sysfs file for card_type\n"); 135120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (device_create_file(&dc->pdev->dev, &dev_attr_open_ttys)) 135220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 135320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "Could not create sysfs file for open_ttys\n"); 135420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 135520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 135620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void remove_sysfs_files(struct nozomi *dc) 135720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 135820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel device_remove_file(&dc->pdev->dev, &dev_attr_card_type); 135920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel device_remove_file(&dc->pdev->dev, &dev_attr_open_ttys); 136020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 136120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 136220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Allocate memory for one device */ 136320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int __devinit nozomi_card_init(struct pci_dev *pdev, 136420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel const struct pci_device_id *ent) 136520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 136620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel resource_size_t start; 136720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ret; 136820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = NULL; 136920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ndev_idx; 137020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 137120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 137220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_dbg(&pdev->dev, "Init, new card found\n"); 137320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 137420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (ndev_idx = 0; ndev_idx < ARRAY_SIZE(ndevs); ndev_idx++) 137520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!ndevs[ndev_idx]) 137620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 137720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 137820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ndev_idx >= ARRAY_SIZE(ndevs)) { 137920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "no free tty range for this card left\n"); 138020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -EIO; 138120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err; 138220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 138320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 138420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc = kzalloc(sizeof(struct nozomi), GFP_KERNEL); 138520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!dc)) { 138620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Could not allocate memory\n"); 138720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -ENOMEM; 138820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_free; 138920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 139020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 139120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->pdev = pdev; 139220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 139320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = pci_enable_device(dc->pdev); 139420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 139520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Failed to enable PCI Device\n"); 139620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_free; 139720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 139820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 139920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = pci_request_regions(dc->pdev, NOZOMI_NAME); 140020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 140120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "I/O address 0x%04x already in use\n", 140220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (int) /* nozomi_private.io_addr */ 0); 140320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_disable_device; 140420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 140520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1406661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel start = pci_resource_start(dc->pdev, 0); 1407661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel if (start == 0) { 1408661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dev_err(&pdev->dev, "No I/O address for card detected\n"); 1409661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel ret = -ENODEV; 1410661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel goto err_rel_regs; 1411661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel } 1412661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1413661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel /* Find out what card type it is */ 1414661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel nozomi_get_card_type(dc); 1415661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 141624cb233520f01971d6d873cb52c64bbbb0665ac0Alan Cox dc->base_addr = ioremap_nocache(start, dc->card_type); 141720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc->base_addr) { 141820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Unable to map card MMIO\n"); 141920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -ENODEV; 142020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_rel_regs; 142120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 142220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 142320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->send_buf = kmalloc(SEND_BUF_MAX, GFP_KERNEL); 142420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc->send_buf) { 142520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "Could not allocate send buffer?\n"); 142620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = -ENOMEM; 142720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto err_free_sbuf; 142820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 142920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14309842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold for (i = PORT_MDM; i < MAX_PORT; i++) { 1431c29bd8d89c9423aed182dbfdb6527b576a2f3552Jiri Slaby if (kfifo_alloc(&dc->port[i].fifo_ul, FIFO_BUFFER_SIZE_UL, 1432c29bd8d89c9423aed182dbfdb6527b576a2f3552Jiri Slaby GFP_KERNEL)) { 14339842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold dev_err(&pdev->dev, 14349842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold "Could not allocate kfifo buffer\n"); 14359842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold ret = -ENOMEM; 14369842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold goto err_free_kfifo; 14379842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold } 14389842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold } 14399842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold 144020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_init(&dc->spin_mutex); 144120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 144220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel nozomi_setup_private_data(dc); 144320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 144420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Disable all interrupts */ 144520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0; 144620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 144720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 144820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = request_irq(pdev->irq, &interrupt_handler, IRQF_SHARED, 144920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel NOZOMI_NAME, dc); 145020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(ret)) { 145120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq); 14529842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold goto err_free_kfifo; 145320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 145420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 145520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("base_addr: %p", dc->base_addr); 145620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 145720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel make_sysfs_files(dc); 145820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 145920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->index_start = ndev_idx * MAX_PORT; 146020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ndevs[ndev_idx] = dc; 146120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1462661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel pci_set_drvdata(pdev, dc); 1463661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1464661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel /* Enable RESET interrupt */ 1465661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->last_ier = RESET; 1466661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel iowrite16(dc->last_ier, dc->reg_ier); 1467661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1468661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel dc->state = NOZOMI_STATE_ENABLED; 1469661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 147020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < MAX_PORT; i++) { 14719842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold struct device *tty_dev; 1472266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = &dc->port[i]; 1473266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox port->dc = dc; 1474266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox tty_port_init(&port->port); 1475266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox port->port.ops = &noz_tty_port_ops; 14769842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold tty_dev = tty_register_device(ntty_driver, dc->index_start + i, 147720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel &pdev->dev); 14789842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold 14799842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold if (IS_ERR(tty_dev)) { 14809842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold ret = PTR_ERR(tty_dev); 14819842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold dev_err(&pdev->dev, "Could not allocate tty?\n"); 14829842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold goto err_free_tty; 14839842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold } 148420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 14859842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold 148620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 148720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 14889842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibolderr_free_tty: 14899842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i) 14909842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold tty_unregister_device(ntty_driver, i); 14919842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibolderr_free_kfifo: 14929842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold for (i = 0; i < MAX_PORT; i++) 14939842c38e917636fa7dc6b88aff17a8f1fd7f0cc0Stefani Seibold kfifo_free(&dc->port[i].fifo_ul); 149420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_free_sbuf: 149520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc->send_buf); 149620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel iounmap(dc->base_addr); 149720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_rel_regs: 149820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_release_regions(pdev); 149920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_disable_device: 150020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_disable_device(pdev); 150120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr_free: 150220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc); 150320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelerr: 150420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ret; 150520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 150620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 150720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void __devexit tty_exit(struct nozomi *dc) 150820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 150920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int i; 151020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 151120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1(" "); 151220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 151333dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox for (i = 0; i < MAX_PORT; ++i) { 151433dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox struct tty_struct *tty = tty_port_tty_get(&dc->port[i].port); 151533dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox if (tty && list_empty(&tty->hangup_work.entry)) 151633dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_hangup(tty); 151733dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox tty_kref_put(tty); 151833dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox } 151933dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox /* Racy below - surely should wait for scheduled work to be done or 152033dd474ae712dc435eb586b44cb771cc8d24e2bdAlan Cox complete off a hangup method ? */ 152120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel while (dc->open_ttys) 152220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel msleep(1); 152320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i) 152420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_unregister_device(ntty_driver, i); 152520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 152620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 152720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Deallocate memory for one device */ 152820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void __devexit nozomi_card_exit(struct pci_dev *pdev) 152920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 153020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int i; 153120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct ctrl_ul ctrl; 153220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = pci_get_drvdata(pdev); 153320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 153420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Disable all interrupts */ 153520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->last_ier = 0; 153620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(dc->last_ier, dc->reg_ier); 153720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 153820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_exit(dc); 153920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 154020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Send 0x0001, command card to resend the reset token. */ 154120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* This is to get the reset when the module is reloaded. */ 154220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.port = 0x00; 154320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.reserved = 0; 154420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.RTS = 0; 154520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ctrl.DTR = 1; 154620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("sending flow control 0x%04X", *((u16 *)&ctrl)); 154720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 154820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* Setup dc->reg addresses to we can use defines here */ 154920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel write_mem32(dc->port[PORT_CTRL].ul_addr[0], (u32 *)&ctrl, 2); 155020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel writew(CTRL_UL, dc->reg_fcr); /* push the token to the card. */ 155120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 155220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel remove_sysfs_files(dc); 155320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 155420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel free_irq(pdev->irq, dc); 155520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 155620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel for (i = 0; i < MAX_PORT; i++) 155745465487897a1c6d508b14b904dc5777f7ec7e04Stefani Seibold kfifo_free(&dc->port[i].fifo_ul); 155820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 155920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc->send_buf); 156020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel iounmap(dc->base_addr); 156220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_release_regions(pdev); 156420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_disable_device(pdev); 156620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ndevs[dc->index_start / MAX_PORT] = NULL; 156820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 156920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel kfree(dc); 157020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 157120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 157220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void set_rts(const struct tty_struct *tty, int rts) 157320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 157420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = get_port_by_tty(tty); 157520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 157620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->ctrl_ul.RTS = rts; 157720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->update_flow_control = 1; 157820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); 157920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 158020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 158120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void set_dtr(const struct tty_struct *tty, int dtr) 158220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 158320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = get_port_by_tty(tty); 158420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 158520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("SETTING DTR index: %d, dtr: %d", tty->index, dtr); 158620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 158720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->ctrl_ul.DTR = dtr; 158820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel port->update_flow_control = 1; 158920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); 159020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 159120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 159220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 159320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * ---------------------------------------------------------------------------- 159420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * TTY code 159520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * ---------------------------------------------------------------------------- 159620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 159720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1598266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic int ntty_install(struct tty_driver *driver, struct tty_struct *tty) 159920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 160020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = get_port_by_tty(tty); 160120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 1602266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox int ret; 1603661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel if (!port || !dc || dc->state != NOZOMI_STATE_READY) 160420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return -ENODEV; 160581f5835eae424be646753ec5a044ed4db1fcc09aJiri Slaby ret = tty_standard_install(driver, tty); 160681f5835eae424be646753ec5a044ed4db1fcc09aJiri Slaby if (ret == 0) 1607bf9c1fca9ae9a79ed209e7ab2c10b3862f3f6f72Jiri Slaby tty->driver_data = port; 1608266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox return ret; 160920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 161020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1611266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic void ntty_cleanup(struct tty_struct *tty) 1612266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1613266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox tty->driver_data = NULL; 1614266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 1615716da631ae91fc5e9f8d5815f8ef5fbfed862b80Alan Cox 1616266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic int ntty_activate(struct tty_port *tport, struct tty_struct *tty) 161720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 1618266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = container_of(tport, struct port, port); 1619266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct nozomi *dc = port->dc; 162020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 162120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1622266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox DBG1("open: %d", port->token_dl); 1623266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox spin_lock_irqsave(&dc->spin_mutex, flags); 1624266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox dc->last_ier = dc->last_ier | port->token_dl; 1625266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox writew(dc->last_ier, dc->reg_ier); 1626266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox dc->open_ttys++; 1627266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox spin_unlock_irqrestore(&dc->spin_mutex, flags); 1628266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox printk("noz: activated %d: %p\n", tty->index, tport); 1629266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox return 0; 1630266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 163120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1632266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic int ntty_open(struct tty_struct *tty, struct file *filp) 1633266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1634bf9c1fca9ae9a79ed209e7ab2c10b3862f3f6f72Jiri Slaby struct port *port = tty->driver_data; 1635266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox return tty_port_open(&port->port, tty, filp); 1636266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 163720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1638266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic void ntty_shutdown(struct tty_port *tport) 1639266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1640266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = container_of(tport, struct port, port); 1641266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct nozomi *dc = port->dc; 1642266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox unsigned long flags; 164320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1644266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox DBG1("close: %d", port->token_dl); 1645266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox spin_lock_irqsave(&dc->spin_mutex, flags); 1646266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox dc->last_ier &= ~(port->token_dl); 1647266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox writew(dc->last_ier, dc->reg_ier); 164820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dc->open_ttys--; 1649266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox spin_unlock_irqrestore(&dc->spin_mutex, flags); 1650266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox printk("noz: shutdown %p\n", tport); 1651266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 165220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1653266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic void ntty_close(struct tty_struct *tty, struct file *filp) 1654266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1655266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = tty->driver_data; 1656266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox if (port) 1657266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox tty_port_close(&port->port, tty, filp); 1658266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox} 1659266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox 1660266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic void ntty_hangup(struct tty_struct *tty) 1661266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox{ 1662266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox struct port *port = tty->driver_data; 1663266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox tty_port_hangup(&port->port); 166420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 166520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 166620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 166720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * called when the userspace process writes to the tty (/dev/noz*). 166825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Data is inserted into a fifo, which is then read and transferred to the modem. 166920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 167020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_write(struct tty_struct *tty, const unsigned char *buffer, 167120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int count) 167220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 167320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int rval = -EINVAL; 167420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 167520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 167620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 167720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 167820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* DBG1( "WRITEx: %d, index = %d", count, index); */ 167920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 168020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!dc || !port) 168120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return -ENODEV; 168220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 16837acd72eb85f1c7a15e8b5eb554994949241737f1Stefani Seibold rval = kfifo_in(&port->fifo_ul, (unsigned char *)buffer, count); 168420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 168520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* notify card */ 168620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(dc == NULL)) { 168720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("No device context?"); 168820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit; 168920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 169020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 169120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 169220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel /* CTS is only valid on the modem channel */ 169320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port == &(dc->port[PORT_MDM])) { 169420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (port->ctrl_dl.CTS) { 169520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG4("Enable interrupt"); 169620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(tty->index % MAX_PORT, dc); 169720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 169820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel dev_err(&dc->pdev->dev, 169920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel "CTS not active on modem port?\n"); 170020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 170120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } else { 170220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_ul(tty->index % MAX_PORT, dc); 170320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 170420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 170520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 170620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelexit: 170720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return rval; 170820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 170920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 171020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 171120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Calculate how much is left in device 171220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * This method is called by the upper tty layer. 171320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * #according to sources N_TTY.c it expects a value >= 0 and 171420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * does not check for negative values. 1715e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox * 1716e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox * If the port is unplugged report lots of room and let the bits 1717e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox * dribble away so we don't block anything. 171820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 171920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_write_room(struct tty_struct *tty) 172020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 172120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 1722e8c65d143a9903cb553c0d80c819428c5b839a02Alan Cox int room = 4096; 172371e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct nozomi *dc = get_dc_by_tty(tty); 172420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 17257fdc28931176a17ef0bdc5d35742925a155533c4Jiri Slaby if (dc) 17266d742f655efe767dc77a099b57297fa417afc473Jiri Slaby room = kfifo_avail(&port->fifo_ul); 17277fdc28931176a17ef0bdc5d35742925a155533c4Jiri Slaby 172820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return room; 172920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 173020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 173120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Gets io control parameters */ 173260b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int ntty_tiocmget(struct tty_struct *tty) 173320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 173471e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct port *port = tty->driver_data; 173571e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct ctrl_dl *ctrl_dl = &port->ctrl_dl; 173671e1b4abdc39b61e4cb73ef74df68ab397e25378Jan Engelhardt const struct ctrl_ul *ctrl_ul = &port->ctrl_ul; 173720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1738978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox /* Note: these could change under us but it is not clear this 1739978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox matters if so */ 174020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return (ctrl_ul->RTS ? TIOCM_RTS : 0) | 174120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_ul->DTR ? TIOCM_DTR : 0) | 174220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->DCD ? TIOCM_CAR : 0) | 174320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->RI ? TIOCM_RNG : 0) | 174420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->DSR ? TIOCM_DSR : 0) | 174520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel (ctrl_dl->CTS ? TIOCM_CTS : 0); 174620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 174720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 174820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Sets io controls parameters */ 174920b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int ntty_tiocmset(struct tty_struct *tty, 175020b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Cox unsigned int set, unsigned int clear) 175120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 1752661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 1753661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel unsigned long flags; 1754661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel 1755661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 175620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (set & TIOCM_RTS) 175720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 1); 175820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel else if (clear & TIOCM_RTS) 175920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 0); 176020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 176120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (set & TIOCM_DTR) 176220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_dtr(tty, 1); 176320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel else if (clear & TIOCM_DTR) 176420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_dtr(tty, 0); 1765661b4e89daf10e3f65a1086fd95c7a84720ccdd2Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 176620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 176720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 176820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 176920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 177020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic int ntty_cflags_changed(struct port *port, unsigned long flags, 177120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct async_icount *cprev) 177220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 177318bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const struct async_icount cnow = port->tty_icount; 177420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ret; 177520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 177620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = ((flags & TIOCM_RNG) && (cnow.rng != cprev->rng)) || 177720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ((flags & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || 177820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ((flags & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || 177920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ((flags & TIOCM_CTS) && (cnow.cts != cprev->cts)); 178020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 178120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel *cprev = cnow; 178220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 178320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ret; 178420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 178520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 17860587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Coxstatic int ntty_tiocgicount(struct tty_struct *tty, 17870587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox struct serial_icounter_struct *icount) 178820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 17890587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox struct port *port = tty->driver_data; 179018bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidel const struct async_icount cnow = port->tty_icount; 17910587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox 17920587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->cts = cnow.cts; 17930587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->dsr = cnow.dsr; 17940587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->rng = cnow.rng; 17950587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->dcd = cnow.dcd; 17960587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->rx = cnow.rx; 17970587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->tx = cnow.tx; 17980587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->frame = cnow.frame; 17990587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->overrun = cnow.overrun; 18000587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->parity = cnow.parity; 18010587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->brk = cnow.brk; 18020587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->buf_overrun = cnow.buf_overrun; 18030587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox return 0; 180420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 180520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 18066caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxstatic int ntty_ioctl(struct tty_struct *tty, 180720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned int cmd, unsigned long arg) 180820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 180920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 181020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int rval = -ENOIOCTLCMD; 181120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 181220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("******** IOCTL, cmd: %d", cmd); 181320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 181420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel switch (cmd) { 181520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel case TIOCMIWAIT: { 181620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct async_icount cprev = port->tty_icount; 181720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 181820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel rval = wait_event_interruptible(port->tty_wait, 181920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_cflags_changed(port, arg, &cprev)); 182020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 18210587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox } 182220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel default: 182320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("ERR: 0x%08X, %d", cmd, cmd); 182420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel break; 182520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel }; 182620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 182720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return rval; 182820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 182920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 183020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 183120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Called by the upper tty layer when tty buffers are ready 183220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * to receive data again after a call to throttle. 183320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 183420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void ntty_unthrottle(struct tty_struct *tty) 183520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 183620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 183720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 183820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 183920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("UNTHROTTLE"); 184020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 184120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel enable_transmit_dl(tty->index % MAX_PORT, dc); 184220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 1); 184320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 184420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 184520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 184620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 184720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* 184820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * Called by the upper tty layer when the tty buffers are almost full. 184920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel * The driver should stop send more data. 185020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel */ 185120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic void ntty_throttle(struct tty_struct *tty) 185220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 185320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 185420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel unsigned long flags; 185520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 185620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel DBG1("THROTTLE"); 185720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_lock_irqsave(&dc->spin_mutex, flags); 185820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel set_rts(tty, 0); 185920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel spin_unlock_irqrestore(&dc->spin_mutex, flags); 186020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 186120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 186220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Returns number of chars in buffer, called by tty layer */ 186320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic s32 ntty_chars_in_buffer(struct tty_struct *tty) 186420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 186520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct port *port = tty->driver_data; 186620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel struct nozomi *dc = get_dc_by_tty(tty); 186723198fda7182969b619613a555f8645fdc3dc334Alan Cox s32 rval = 0; 186820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 186920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (unlikely(!dc || !port)) { 187020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto exit_in_buffer; 187120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 187220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1873e64c026dd09b73faf20707711402fc5ed55a8e70Stefani Seibold rval = kfifo_len(&port->fifo_ul); 187420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 187520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelexit_in_buffer: 187620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return rval; 187720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 187820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 1879266794eb71cfee65b38371954b9db2f6dbda207cAlan Coxstatic const struct tty_port_operations noz_tty_port_ops = { 1880266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .activate = ntty_activate, 1881266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .shutdown = ntty_shutdown, 1882266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox}; 1883266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox 188418bbe0c26ccb7445d19465b0d3585d23445307f1Frank Seidelstatic const struct tty_operations tty_ops = { 188520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .ioctl = ntty_ioctl, 188620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .open = ntty_open, 188720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .close = ntty_close, 1888266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .hangup = ntty_hangup, 188920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .write = ntty_write, 189020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .write_room = ntty_write_room, 189120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .unthrottle = ntty_unthrottle, 189220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .throttle = ntty_throttle, 189320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .chars_in_buffer = ntty_chars_in_buffer, 189420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .tiocmget = ntty_tiocmget, 189520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .tiocmset = ntty_tiocmset, 18960587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox .get_icount = ntty_tiocgicount, 1897266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .install = ntty_install, 1898266794eb71cfee65b38371954b9db2f6dbda207cAlan Cox .cleanup = ntty_cleanup, 189920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 190020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 190120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel/* Module initialization */ 190220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic struct pci_driver nozomi_driver = { 190320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .name = NOZOMI_NAME, 190420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .id_table = nozomi_pci_tbl, 190520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .probe = nozomi_card_init, 190620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel .remove = __devexit_p(nozomi_card_exit), 190720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel}; 190820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 190920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic __init int nozomi_init(void) 191020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 191120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel int ret; 191220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 191320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_INFO "Initializing %s\n", VERSION_STRING); 191420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 191520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver = alloc_tty_driver(NTTY_TTY_MAXMINORS); 191620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (!ntty_driver) 191720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return -ENOMEM; 191820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 191920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->driver_name = NOZOMI_NAME_TTY; 192020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->name = "noz"; 192120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->major = 0; 192220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->type = TTY_DRIVER_TYPE_SERIAL; 192320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->subtype = SERIAL_TYPE_NORMAL; 192420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 192520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios = tty_std_termios; 192620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | \ 192720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel HUPCL | CLOCAL; 192820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios.c_ispeed = 115200; 192920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ntty_driver->init_termios.c_ospeed = 115200; 193020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_set_operations(ntty_driver, &tty_ops); 193120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 193220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = tty_register_driver(ntty_driver); 193320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 193420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_ERR "Nozomi: failed to register ntty driver\n"); 193520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto free_tty; 193620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 193720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 193820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel ret = pci_register_driver(&nozomi_driver); 193920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel if (ret) { 194020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_ERR "Nozomi: can't register pci driver\n"); 194120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel goto unr_tty; 194220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel } 194320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 194420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return 0; 194520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelunr_tty: 194620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_unregister_driver(ntty_driver); 194720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelfree_tty: 194820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel put_tty_driver(ntty_driver); 194920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel return ret; 195020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 195120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 195220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelstatic __exit void nozomi_exit(void) 195320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel{ 195420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel printk(KERN_INFO "Unloading %s\n", DRIVER_DESC); 195520fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel pci_unregister_driver(&nozomi_driver); 195620fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel tty_unregister_driver(ntty_driver); 195720fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel put_tty_driver(ntty_driver); 195820fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel} 195920fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 196020fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelmodule_init(nozomi_init); 196120fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelmodule_exit(nozomi_exit); 196220fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 196320fd1e3bea554620d489f3542496639c1babe0b3Frank Seidelmodule_param(debug, int, S_IRUGO | S_IWUSR); 196420fd1e3bea554620d489f3542496639c1babe0b3Frank Seidel 196520fd1e3bea554620d489f3542496639c1babe0b3Frank SeidelMODULE_LICENSE("Dual BSD/GPL"); 196620fd1e3bea554620d489f3542496639c1babe0b3Frank SeidelMODULE_DESCRIPTION(DRIVER_DESC); 1967