From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 19877C61DA4 for ; Wed, 22 Feb 2023 08:51:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231437AbjBVIvg (ORCPT ); Wed, 22 Feb 2023 03:51:36 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40674 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231425AbjBVIve (ORCPT ); Wed, 22 Feb 2023 03:51:34 -0500 Received: from mail-ed1-f43.google.com (mail-ed1-f43.google.com [209.85.208.43]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 520CB37B6C for ; Wed, 22 Feb 2023 00:51:28 -0800 (PST) Received: by mail-ed1-f43.google.com with SMTP id h16so27486850edz.10 for ; Wed, 22 Feb 2023 00:51:28 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:in-reply-to:from:references:cc:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=K1cqToQF+gbtZH429+Dt025YP8cfNqzb8D7xw6u0YLg=; b=rOiL38SkIT/9V/Izw6MF4pWsr7QnrvxzYF6/2UbSVCrsqbVpez/2A9DHa+NYWZmy20 8rYQ6IDN7XAdji5KrmkwtFyT+y2qhRmABaGYZNiY9dQykE0F8Ynl4ciZW74Rzc5qa5Kj z4P00CUdwHw7NCfgwmIuXvNqsOk52wr+ImWS8ZOInasLBUp3BtffXldKCVZ8KRhCun5y OKQeTpFnLJaPXfVnjWKy7CThJ2a+ecgBdcZJuDmmUleMekoF7803EmyfkOyIppZ4stuf 5S+U+gzIRlo7CQwsXjMAH5eXNta16lgV467p+09ESew6ecughdwycOcuR3F/CUH3Zhu2 v9uw== X-Gm-Message-State: AO0yUKVAWzdc2yP+DSDq1FMRmJdEGjcsJbNYPYqdbHuAXlwAlkHeUjxz r4fwQ+gKhzmQh4bWh3v01s8= X-Google-Smtp-Source: AK7set/Oe0ilrCduDXMubHXawnYOsO3LQ1v5kLtieWeVvyL2cmhpV4eerO4cTbCRf/2AFIDJueBa5w== X-Received: by 2002:a17:907:a801:b0:8aa:c0a4:2aa5 with SMTP id vo1-20020a170907a80100b008aac0a42aa5mr16332686ejc.16.1677055886178; Wed, 22 Feb 2023 00:51:26 -0800 (PST) Received: from ?IPV6:2a0b:e7c0:0:107::aaaa:49? ([2a0b:e7c0:0:107::aaaa:49]) by smtp.gmail.com with ESMTPSA id g9-20020a170906348900b008b11ba87bf4sm6961528ejb.209.2023.02.22.00.51.25 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 22 Feb 2023 00:51:25 -0800 (PST) Message-ID: <63f5c934-24da-b17e-dc6d-8bf5ca31dbd6@kernel.org> Date: Wed, 22 Feb 2023 09:51:24 +0100 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.7.1 Subject: Re: [PATCH 2/2] char: pcmcia: remove all the drivers Content-Language: en-US To: gregkh@linuxfoundation.org Cc: linux-kernel@vger.kernel.org, Hyunwoo Kim , Harald Welte , Lubomir Rintel , Arnd Bergmann References: <20230222085013.32331-1-jirislaby@kernel.org> <20230222085013.32331-2-jirislaby@kernel.org> From: Jiri Slaby In-Reply-To: <20230222085013.32331-2-jirislaby@kernel.org> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org I forgot to amend, please ignore this. On 22. 02. 23, 9:50, Jiri Slaby (SUSE) wrote: > These char PCMCIA drivers are buggy[1] and receive only minimal care. It > was concluded[2], that we should try to remove most pcmcia drivers > completely. Let's start with these char broken one. > > Note that I also removed a UAPI header: include/uapi/linux/cm4000_cs.h. > I found only coccinelle tests mentioning some ioctl constants from that > file. But they are not actually used. Anyway, should someone complain, > we may reintroduce the header (or its parts). > > [1] https://lore.kernel.org/all/f41c2765-80e0-48bc-b1e4-8cfd3230fd4a@www.fastmail.com/ > [2] https://lore.kernel.org/all/c5b39544-a4fb-4796-a046-0b9be9853787@app.fastmail.com/ > > Signed-off-by: Jiri Slaby (SUSE) > Cc: "Hyunwoo Kim" > Cc: Harald Welte > Cc: Lubomir Rintel > Cc: Arnd Bergmann > Cc: Greg Kroah-Hartman > --- > Documentation/process/magic-number.rst | 1 - > .../it_IT/process/magic-number.rst | 1 - > .../sp_SP/process/magic-number.rst | 1 - > .../zh_CN/process/magic-number.rst | 1 - > .../zh_TW/process/magic-number.rst | 1 - > .../userspace-api/ioctl/ioctl-number.rst | 1 - > MAINTAINERS | 17 - > arch/powerpc/configs/ppc6xx_defconfig | 2 - > drivers/char/Makefile | 1 - > drivers/char/pcmcia/Kconfig | 59 - > drivers/char/pcmcia/Makefile | 11 - > drivers/char/pcmcia/cm4000_cs.c | 1912 -------- > drivers/char/pcmcia/cm4040_cs.c | 684 --- > drivers/char/pcmcia/cm4040_cs.h | 48 - > drivers/char/pcmcia/scr24x_cs.c | 359 -- > drivers/char/pcmcia/synclink_cs.c | 4280 ----------------- > include/linux/cm4000_cs.h | 11 - > 17 files changed, 7390 deletions(-) > delete mode 100644 drivers/char/pcmcia/Kconfig > delete mode 100644 drivers/char/pcmcia/Makefile > delete mode 100644 drivers/char/pcmcia/cm4000_cs.c > delete mode 100644 drivers/char/pcmcia/cm4040_cs.c > delete mode 100644 drivers/char/pcmcia/cm4040_cs.h > delete mode 100644 drivers/char/pcmcia/scr24x_cs.c > delete mode 100644 drivers/char/pcmcia/synclink_cs.c > delete mode 100644 include/linux/cm4000_cs.h > > diff --git a/Documentation/process/magic-number.rst b/Documentation/process/magic-number.rst > index 64b5948fc1d4..7029c3c084ee 100644 > --- a/Documentation/process/magic-number.rst > +++ b/Documentation/process/magic-number.rst > @@ -72,7 +72,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/ > APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` > FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` > SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` > -MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` > BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` > HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` > KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` > diff --git a/Documentation/translations/it_IT/process/magic-number.rst b/Documentation/translations/it_IT/process/magic-number.rst > index 02eb7eb2448e..ae92ab633c16 100644 > --- a/Documentation/translations/it_IT/process/magic-number.rst > +++ b/Documentation/translations/it_IT/process/magic-number.rst > @@ -78,7 +78,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/ > APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` > FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` > SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` > -MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` > BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` > HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` > KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` > diff --git a/Documentation/translations/sp_SP/process/magic-number.rst b/Documentation/translations/sp_SP/process/magic-number.rst > index 2b62cec34e8e..7c7dfb4ba80b 100644 > --- a/Documentation/translations/sp_SP/process/magic-number.rst > +++ b/Documentation/translations/sp_SP/process/magic-number.rst > @@ -77,7 +77,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/ > APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` > FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` > SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` > -MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` > BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` > HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` > KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` > diff --git a/Documentation/translations/zh_CN/process/magic-number.rst b/Documentation/translations/zh_CN/process/magic-number.rst > index 0617ce125e12..37ed33034134 100644 > --- a/Documentation/translations/zh_CN/process/magic-number.rst > +++ b/Documentation/translations/zh_CN/process/magic-number.rst > @@ -61,7 +61,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/ > APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` > FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` > SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` > -MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` > BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` > HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` > KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` > diff --git a/Documentation/translations/zh_TW/process/magic-number.rst b/Documentation/translations/zh_TW/process/magic-number.rst > index f3f7082e17c6..1d48e1bbf5f2 100644 > --- a/Documentation/translations/zh_TW/process/magic-number.rst > +++ b/Documentation/translations/zh_TW/process/magic-number.rst > @@ -64,7 +64,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/ > APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` > FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` > SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` > -MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` > BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` > HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` > KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` > diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst > index 0a1882e296ae..176e8fc3f31b 100644 > --- a/Documentation/userspace-api/ioctl/ioctl-number.rst > +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst > @@ -222,7 +222,6 @@ Code Seq# Include File Comments > 'b' 00-FF conflict! bit3 vme host bridge > > 'b' 00-0F linux/dma-buf.h conflict! > -'c' all linux/cm4000_cs.h conflict! > 'c' 00-7F linux/comstats.h conflict! > 'c' 00-7F linux/coda.h conflict! > 'c' 00-1F linux/chio.h conflict! > diff --git a/MAINTAINERS b/MAINTAINERS > index 2f78e795e1fd..4e27fd843be9 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -15260,18 +15260,6 @@ S: Maintained > F: Documentation/filesystems/omfs.rst > F: fs/omfs/ > > -OMNIKEY CARDMAN 4000 DRIVER > -M: Harald Welte > -S: Maintained > -F: drivers/char/pcmcia/cm4000_cs.c > -F: include/linux/cm4000_cs.h > -F: include/uapi/linux/cm4000_cs.h > - > -OMNIKEY CARDMAN 4040 DRIVER > -M: Harald Welte > -S: Maintained > -F: drivers/char/pcmcia/cm4040_cs.* > - > OMNIVISION OG01A1B SENSOR DRIVER > M: Shawn Tu > L: linux-media@vger.kernel.org > @@ -18524,11 +18512,6 @@ F: include/linux/wait.h > F: include/uapi/linux/sched.h > F: kernel/sched/ > > -SCR24X CHIP CARD INTERFACE DRIVER > -M: Lubomir Rintel > -S: Supported > -F: drivers/char/pcmcia/scr24x_cs.c > - > SCSI RDMA PROTOCOL (SRP) INITIATOR > M: Bart Van Assche > L: linux-rdma@vger.kernel.org > diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig > index 110258277959..d8729b94400e 100644 > --- a/arch/powerpc/configs/ppc6xx_defconfig > +++ b/arch/powerpc/configs/ppc6xx_defconfig > @@ -614,8 +614,6 @@ CONFIG_HW_RANDOM=y > CONFIG_HW_RANDOM_VIRTIO=m > CONFIG_NVRAM=y > CONFIG_DTLK=m > -CONFIG_CARDMAN_4000=m > -CONFIG_CARDMAN_4040=m > CONFIG_IPWIRELESS=m > CONFIG_I2C_CHARDEV=m > CONFIG_I2C_HYDRA=m > diff --git a/drivers/char/Makefile b/drivers/char/Makefile > index b5271efd32ef..22ae5935dd2e 100644 > --- a/drivers/char/Makefile > +++ b/drivers/char/Makefile > @@ -36,7 +36,6 @@ obj-$(CONFIG_TELCLOCK) += tlclk.o > > obj-$(CONFIG_MWAVE) += mwave/ > obj-y += agp/ > -obj-$(CONFIG_PCMCIA) += pcmcia/ > > obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o > obj-$(CONFIG_TCG_TPM) += tpm/ > diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig > deleted file mode 100644 > index 26724990074c..000000000000 > --- a/drivers/char/pcmcia/Kconfig > +++ /dev/null > @@ -1,59 +0,0 @@ > -# SPDX-License-Identifier: GPL-2.0-only > -# > -# PCMCIA character device configuration > -# > - > -menu "PCMCIA character devices" > - depends on PCMCIA!=n > - > -config SYNCLINK_CS > - tristate "SyncLink PC Card support" > - depends on PCMCIA && TTY > - help > - Enable support for the SyncLink PC Card serial adapter, running > - asynchronous and HDLC communications up to 512Kbps. The port is > - selectable for RS-232, V.35, RS-449, RS-530, and X.21 > - > - This driver may be built as a module ( = code which can be > - inserted in and removed from the running kernel whenever you want). > - The module will be called synclink_cs. If you want to do that, say M > - here. > - > -config CARDMAN_4000 > - tristate "Omnikey Cardman 4000 support" > - depends on PCMCIA > - select BITREVERSE > - help > - Enable support for the Omnikey Cardman 4000 PCMCIA Smartcard > - reader. > - > - This kernel driver requires additional userspace support, either > - by the vendor-provided PC/SC ifd_handler (http://www.omnikey.com/), > - or via the cm4000 backend of OpenCT (http://www.opensc-project.org/opensc). > - > -config CARDMAN_4040 > - tristate "Omnikey CardMan 4040 support" > - depends on PCMCIA > - help > - Enable support for the Omnikey CardMan 4040 PCMCIA Smartcard > - reader. > - > - This card is basically a USB CCID device connected to a FIFO > - in I/O space. To use the kernel driver, you will need either the > - PC/SC ifdhandler provided from the Omnikey homepage > - (http://www.omnikey.com/), or a current development version of OpenCT > - (http://www.opensc-project.org/opensc). > - > -config SCR24X > - tristate "SCR24x Chip Card Interface support" > - depends on PCMCIA > - help > - Enable support for the SCR24x PCMCIA Chip Card Interface. > - > - To compile this driver as a module, choose M here. > - The module will be called scr24x_cs.. > - > - If unsure say N. > - > -endmenu > - > diff --git a/drivers/char/pcmcia/Makefile b/drivers/char/pcmcia/Makefile > deleted file mode 100644 > index 024eed1c4ca5..000000000000 > --- a/drivers/char/pcmcia/Makefile > +++ /dev/null > @@ -1,11 +0,0 @@ > -# SPDX-License-Identifier: GPL-2.0-only > -# > -# drivers/char/pcmcia/Makefile > -# > -# Makefile for the Linux PCMCIA char device drivers. > -# > - > -obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o > -obj-$(CONFIG_CARDMAN_4000) += cm4000_cs.o > -obj-$(CONFIG_CARDMAN_4040) += cm4040_cs.o > -obj-$(CONFIG_SCR24X) += scr24x_cs.o > diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c > deleted file mode 100644 > index e656f42a28ac..000000000000 > --- a/drivers/char/pcmcia/cm4000_cs.c > +++ /dev/null > @@ -1,1912 +0,0 @@ > - /* > - * A driver for the PCMCIA Smartcard Reader "Omnikey CardMan Mobile 4000" > - * > - * cm4000_cs.c support.linux@omnikey.com > - * > - * Tue Oct 23 11:32:43 GMT 2001 herp - cleaned up header files > - * Sun Jan 20 10:11:15 MET 2002 herp - added modversion header files > - * Thu Nov 14 16:34:11 GMT 2002 mh - added PPS functionality > - * Tue Nov 19 16:36:27 GMT 2002 mh - added SUSPEND/RESUME functionailty > - * Wed Jul 28 12:55:01 CEST 2004 mh - kernel 2.6 adjustments > - * > - * current version: 2.4.0gm4 > - * > - * (C) 2000,2001,2002,2003,2004 Omnikey AG > - * > - * (C) 2005-2006 Harald Welte > - * - Adhere to Kernel process/coding-style.rst > - * - Port to 2.6.13 "new" style PCMCIA > - * - Check for copy_{from,to}_user return values > - * - Use nonseekable_open() > - * - add class interface for udev device creation > - * > - * All rights reserved. Licensed under dual BSD/GPL license. > - */ > - > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > - > -#include > -#include > -#include > -#include > - > -#include > - > -/* #define ATR_CSUM */ > - > -#define reader_to_dev(x) (&x->p_dev->dev) > - > -/* n (debug level) is ignored */ > -/* additional debug output may be enabled by re-compiling with > - * CM4000_DEBUG set */ > -/* #define CM4000_DEBUG */ > -#define DEBUGP(n, rdr, x, args...) do { \ > - dev_dbg(reader_to_dev(rdr), "%s:" x, \ > - __func__ , ## args); \ > - } while (0) > - > -static DEFINE_MUTEX(cmm_mutex); > - > -#define T_1SEC (HZ) > -#define T_10MSEC msecs_to_jiffies(10) > -#define T_20MSEC msecs_to_jiffies(20) > -#define T_40MSEC msecs_to_jiffies(40) > -#define T_50MSEC msecs_to_jiffies(50) > -#define T_100MSEC msecs_to_jiffies(100) > -#define T_500MSEC msecs_to_jiffies(500) > - > -static void cm4000_release(struct pcmcia_device *link); > - > -static int major; /* major number we get from the kernel */ > - > -/* note: the first state has to have number 0 always */ > - > -#define M_FETCH_ATR 0 > -#define M_TIMEOUT_WAIT 1 > -#define M_READ_ATR_LEN 2 > -#define M_READ_ATR 3 > -#define M_ATR_PRESENT 4 > -#define M_BAD_CARD 5 > -#define M_CARDOFF 6 > - > -#define LOCK_IO 0 > -#define LOCK_MONITOR 1 > - > -#define IS_AUTOPPS_ACT 6 > -#define IS_PROCBYTE_PRESENT 7 > -#define IS_INVREV 8 > -#define IS_ANY_T0 9 > -#define IS_ANY_T1 10 > -#define IS_ATR_PRESENT 11 > -#define IS_ATR_VALID 12 > -#define IS_CMM_ABSENT 13 > -#define IS_BAD_LENGTH 14 > -#define IS_BAD_CSUM 15 > -#define IS_BAD_CARD 16 > - > -#define REG_FLAGS0(x) (x + 0) > -#define REG_FLAGS1(x) (x + 1) > -#define REG_NUM_BYTES(x) (x + 2) > -#define REG_BUF_ADDR(x) (x + 3) > -#define REG_BUF_DATA(x) (x + 4) > -#define REG_NUM_SEND(x) (x + 5) > -#define REG_BAUDRATE(x) (x + 6) > -#define REG_STOPBITS(x) (x + 7) > - > -struct cm4000_dev { > - struct pcmcia_device *p_dev; > - > - unsigned char atr[MAX_ATR]; > - unsigned char rbuf[512]; > - unsigned char sbuf[512]; > - > - wait_queue_head_t devq; /* when removing cardman must not be > - zeroed! */ > - > - wait_queue_head_t ioq; /* if IO is locked, wait on this Q */ > - wait_queue_head_t atrq; /* wait for ATR valid */ > - wait_queue_head_t readq; /* used by write to wake blk.read */ > - > - /* warning: do not move this struct group. > - * initialising to zero depends on it - see ZERO_DEV below. */ > - struct_group(init, > - unsigned char atr_csum; > - unsigned char atr_len_retry; > - unsigned short atr_len; > - unsigned short rlen; /* bytes avail. after write */ > - unsigned short rpos; /* latest read pos. write zeroes */ > - unsigned char procbyte; /* T=0 procedure byte */ > - unsigned char mstate; /* state of card monitor */ > - unsigned char cwarn; /* slow down warning */ > - unsigned char flags0; /* cardman IO-flags 0 */ > - unsigned char flags1; /* cardman IO-flags 1 */ > - unsigned int mdelay; /* variable monitor speeds, in jiffies */ > - > - unsigned int baudv; /* baud value for speed */ > - unsigned char ta1; > - unsigned char proto; /* T=0, T=1, ... */ > - unsigned long flags; /* lock+flags (MONITOR,IO,ATR) * for concurrent > - access */ > - > - unsigned char pts[4]; > - > - struct timer_list timer; /* used to keep monitor running */ > - int monitor_running; > - ); > -}; > - > -#define ZERO_DEV(dev) memset(&((dev)->init), 0, sizeof((dev)->init)) > - > -static struct pcmcia_device *dev_table[CM4000_MAX_DEV]; > -static struct class *cmm_class; > - > -/* This table doesn't use spaces after the comma between fields and thus > - * violates process/coding-style.rst. However, I don't really think wrapping it around will > - * make it any clearer to read -HW */ > -static unsigned char fi_di_table[10][14] = { > -/*FI 00 01 02 03 04 05 06 07 08 09 10 11 12 13 */ > -/*DI */ > -/* 0 */ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11}, > -/* 1 */ {0x01,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x91,0x11,0x11,0x11,0x11}, > -/* 2 */ {0x02,0x12,0x22,0x32,0x11,0x11,0x11,0x11,0x11,0x92,0xA2,0xB2,0x11,0x11}, > -/* 3 */ {0x03,0x13,0x23,0x33,0x43,0x53,0x63,0x11,0x11,0x93,0xA3,0xB3,0xC3,0xD3}, > -/* 4 */ {0x04,0x14,0x24,0x34,0x44,0x54,0x64,0x11,0x11,0x94,0xA4,0xB4,0xC4,0xD4}, > -/* 5 */ {0x00,0x15,0x25,0x35,0x45,0x55,0x65,0x11,0x11,0x95,0xA5,0xB5,0xC5,0xD5}, > -/* 6 */ {0x06,0x16,0x26,0x36,0x46,0x56,0x66,0x11,0x11,0x96,0xA6,0xB6,0xC6,0xD6}, > -/* 7 */ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11}, > -/* 8 */ {0x08,0x11,0x28,0x38,0x48,0x58,0x68,0x11,0x11,0x98,0xA8,0xB8,0xC8,0xD8}, > -/* 9 */ {0x09,0x19,0x29,0x39,0x49,0x59,0x69,0x11,0x11,0x99,0xA9,0xB9,0xC9,0xD9} > -}; > - > -#ifndef CM4000_DEBUG > -#define xoutb outb > -#define xinb inb > -#else > -static inline void xoutb(unsigned char val, unsigned short port) > -{ > - pr_debug("outb(val=%.2x,port=%.4x)\n", val, port); > - outb(val, port); > -} > -static inline unsigned char xinb(unsigned short port) > -{ > - unsigned char val; > - > - val = inb(port); > - pr_debug("%.2x=inb(%.4x)\n", val, port); > - > - return val; > -} > -#endif > - > -static inline unsigned char invert_revert(unsigned char ch) > -{ > - return bitrev8(~ch); > -} > - > -static void str_invert_revert(unsigned char *b, int len) > -{ > - int i; > - > - for (i = 0; i < len; i++) > - b[i] = invert_revert(b[i]); > -} > - > -#define ATRLENCK(dev,pos) \ > - if (pos>=dev->atr_len || pos>=MAX_ATR) \ > - goto return_0; > - > -static unsigned int calc_baudv(unsigned char fidi) > -{ > - unsigned int wcrcf, wbrcf, fi_rfu, di_rfu; > - > - fi_rfu = 372; > - di_rfu = 1; > - > - /* FI */ > - switch ((fidi >> 4) & 0x0F) { > - case 0x00: > - wcrcf = 372; > - break; > - case 0x01: > - wcrcf = 372; > - break; > - case 0x02: > - wcrcf = 558; > - break; > - case 0x03: > - wcrcf = 744; > - break; > - case 0x04: > - wcrcf = 1116; > - break; > - case 0x05: > - wcrcf = 1488; > - break; > - case 0x06: > - wcrcf = 1860; > - break; > - case 0x07: > - wcrcf = fi_rfu; > - break; > - case 0x08: > - wcrcf = fi_rfu; > - break; > - case 0x09: > - wcrcf = 512; > - break; > - case 0x0A: > - wcrcf = 768; > - break; > - case 0x0B: > - wcrcf = 1024; > - break; > - case 0x0C: > - wcrcf = 1536; > - break; > - case 0x0D: > - wcrcf = 2048; > - break; > - default: > - wcrcf = fi_rfu; > - break; > - } > - > - /* DI */ > - switch (fidi & 0x0F) { > - case 0x00: > - wbrcf = di_rfu; > - break; > - case 0x01: > - wbrcf = 1; > - break; > - case 0x02: > - wbrcf = 2; > - break; > - case 0x03: > - wbrcf = 4; > - break; > - case 0x04: > - wbrcf = 8; > - break; > - case 0x05: > - wbrcf = 16; > - break; > - case 0x06: > - wbrcf = 32; > - break; > - case 0x07: > - wbrcf = di_rfu; > - break; > - case 0x08: > - wbrcf = 12; > - break; > - case 0x09: > - wbrcf = 20; > - break; > - default: > - wbrcf = di_rfu; > - break; > - } > - > - return (wcrcf / wbrcf); > -} > - > -static unsigned short io_read_num_rec_bytes(unsigned int iobase, > - unsigned short *s) > -{ > - unsigned short tmp; > - > - tmp = *s = 0; > - do { > - *s = tmp; > - tmp = inb(REG_NUM_BYTES(iobase)) | > - (inb(REG_FLAGS0(iobase)) & 4 ? 0x100 : 0); > - } while (tmp != *s); > - > - return *s; > -} > - > -static int parse_atr(struct cm4000_dev *dev) > -{ > - unsigned char any_t1, any_t0; > - unsigned char ch, ifno; > - int ix, done; > - > - DEBUGP(3, dev, "-> parse_atr: dev->atr_len = %i\n", dev->atr_len); > - > - if (dev->atr_len < 3) { > - DEBUGP(5, dev, "parse_atr: atr_len < 3\n"); > - return 0; > - } > - > - if (dev->atr[0] == 0x3f) > - set_bit(IS_INVREV, &dev->flags); > - else > - clear_bit(IS_INVREV, &dev->flags); > - ix = 1; > - ifno = 1; > - ch = dev->atr[1]; > - dev->proto = 0; /* XXX PROTO */ > - any_t1 = any_t0 = done = 0; > - dev->ta1 = 0x11; /* defaults to 9600 baud */ > - do { > - if (ifno == 1 && (ch & 0x10)) { > - /* read first interface byte and TA1 is present */ > - dev->ta1 = dev->atr[2]; > - DEBUGP(5, dev, "Card says FiDi is 0x%.2x\n", dev->ta1); > - ifno++; > - } else if ((ifno == 2) && (ch & 0x10)) { /* TA(2) */ > - dev->ta1 = 0x11; > - ifno++; > - } > - > - DEBUGP(5, dev, "Yi=%.2x\n", ch & 0xf0); > - ix += ((ch & 0x10) >> 4) /* no of int.face chars */ > - +((ch & 0x20) >> 5) > - + ((ch & 0x40) >> 6) > - + ((ch & 0x80) >> 7); > - /* ATRLENCK(dev,ix); */ > - if (ch & 0x80) { /* TDi */ > - ch = dev->atr[ix]; > - if ((ch & 0x0f)) { > - any_t1 = 1; > - DEBUGP(5, dev, "card is capable of T=1\n"); > - } else { > - any_t0 = 1; > - DEBUGP(5, dev, "card is capable of T=0\n"); > - } > - } else > - done = 1; > - } while (!done); > - > - DEBUGP(5, dev, "ix=%d noHist=%d any_t1=%d\n", > - ix, dev->atr[1] & 15, any_t1); > - if (ix + 1 + (dev->atr[1] & 0x0f) + any_t1 != dev->atr_len) { > - DEBUGP(5, dev, "length error\n"); > - return 0; > - } > - if (any_t0) > - set_bit(IS_ANY_T0, &dev->flags); > - > - if (any_t1) { /* compute csum */ > - dev->atr_csum = 0; > -#ifdef ATR_CSUM > - for (i = 1; i < dev->atr_len; i++) > - dev->atr_csum ^= dev->atr[i]; > - if (dev->atr_csum) { > - set_bit(IS_BAD_CSUM, &dev->flags); > - DEBUGP(5, dev, "bad checksum\n"); > - goto return_0; > - } > -#endif > - if (any_t0 == 0) > - dev->proto = 1; /* XXX PROTO */ > - set_bit(IS_ANY_T1, &dev->flags); > - } > - > - return 1; > -} > - > -struct card_fixup { > - char atr[12]; > - u_int8_t atr_len; > - u_int8_t stopbits; > -}; > - > -static struct card_fixup card_fixups[] = { > - { /* ACOS */ > - .atr = { 0x3b, 0xb3, 0x11, 0x00, 0x00, 0x41, 0x01 }, > - .atr_len = 7, > - .stopbits = 0x03, > - }, > - { /* Motorola */ > - .atr = {0x3b, 0x76, 0x13, 0x00, 0x00, 0x80, 0x62, 0x07, > - 0x41, 0x81, 0x81 }, > - .atr_len = 11, > - .stopbits = 0x04, > - }, > -}; > - > -static void set_cardparameter(struct cm4000_dev *dev) > -{ > - int i; > - unsigned int iobase = dev->p_dev->resource[0]->start; > - u_int8_t stopbits = 0x02; /* ISO default */ > - > - DEBUGP(3, dev, "-> set_cardparameter\n"); > - > - dev->flags1 = dev->flags1 | (((dev->baudv - 1) & 0x0100) >> 8); > - xoutb(dev->flags1, REG_FLAGS1(iobase)); > - DEBUGP(5, dev, "flags1 = 0x%02x\n", dev->flags1); > - > - /* set baudrate */ > - xoutb((unsigned char)((dev->baudv - 1) & 0xFF), REG_BAUDRATE(iobase)); > - > - DEBUGP(5, dev, "baudv = %i -> write 0x%02x\n", dev->baudv, > - ((dev->baudv - 1) & 0xFF)); > - > - /* set stopbits */ > - for (i = 0; i < ARRAY_SIZE(card_fixups); i++) { > - if (!memcmp(dev->atr, card_fixups[i].atr, > - card_fixups[i].atr_len)) > - stopbits = card_fixups[i].stopbits; > - } > - xoutb(stopbits, REG_STOPBITS(iobase)); > - > - DEBUGP(3, dev, "<- set_cardparameter\n"); > -} > - > -static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq) > -{ > - > - unsigned long tmp, i; > - unsigned short num_bytes_read; > - unsigned char pts_reply[4]; > - ssize_t rc; > - unsigned int iobase = dev->p_dev->resource[0]->start; > - > - rc = 0; > - > - DEBUGP(3, dev, "-> set_protocol\n"); > - DEBUGP(5, dev, "ptsreq->Protocol = 0x%.8x, ptsreq->Flags=0x%.8x, " > - "ptsreq->pts1=0x%.2x, ptsreq->pts2=0x%.2x, " > - "ptsreq->pts3=0x%.2x\n", (unsigned int)ptsreq->protocol, > - (unsigned int)ptsreq->flags, ptsreq->pts1, ptsreq->pts2, > - ptsreq->pts3); > - > - /* Fill PTS structure */ > - dev->pts[0] = 0xff; > - dev->pts[1] = 0x00; > - tmp = ptsreq->protocol; > - while ((tmp = (tmp >> 1)) > 0) > - dev->pts[1]++; > - dev->proto = dev->pts[1]; /* Set new protocol */ > - dev->pts[1] = (0x01 << 4) | (dev->pts[1]); > - > - /* Correct Fi/Di according to CM4000 Fi/Di table */ > - DEBUGP(5, dev, "Ta(1) from ATR is 0x%.2x\n", dev->ta1); > - /* set Fi/Di according to ATR TA(1) */ > - dev->pts[2] = fi_di_table[dev->ta1 & 0x0F][(dev->ta1 >> 4) & 0x0F]; > - > - /* Calculate PCK character */ > - dev->pts[3] = dev->pts[0] ^ dev->pts[1] ^ dev->pts[2]; > - > - DEBUGP(5, dev, "pts0=%.2x, pts1=%.2x, pts2=%.2x, pts3=%.2x\n", > - dev->pts[0], dev->pts[1], dev->pts[2], dev->pts[3]); > - > - /* check card convention */ > - if (test_bit(IS_INVREV, &dev->flags)) > - str_invert_revert(dev->pts, 4); > - > - /* reset SM */ > - xoutb(0x80, REG_FLAGS0(iobase)); > - > - /* Enable access to the message buffer */ > - DEBUGP(5, dev, "Enable access to the messages buffer\n"); > - dev->flags1 = 0x20 /* T_Active */ > - | (test_bit(IS_INVREV, &dev->flags) ? 0x02 : 0x00) /* inv parity */ > - | ((dev->baudv >> 8) & 0x01); /* MSB-baud */ > - xoutb(dev->flags1, REG_FLAGS1(iobase)); > - > - DEBUGP(5, dev, "Enable message buffer -> flags1 = 0x%.2x\n", > - dev->flags1); > - > - /* write challenge to the buffer */ > - DEBUGP(5, dev, "Write challenge to buffer: "); > - for (i = 0; i < 4; i++) { > - xoutb(i, REG_BUF_ADDR(iobase)); > - xoutb(dev->pts[i], REG_BUF_DATA(iobase)); /* buf data */ > -#ifdef CM4000_DEBUG > - pr_debug("0x%.2x ", dev->pts[i]); > - } > - pr_debug("\n"); > -#else > - } > -#endif > - > - /* set number of bytes to write */ > - DEBUGP(5, dev, "Set number of bytes to write\n"); > - xoutb(0x04, REG_NUM_SEND(iobase)); > - > - /* Trigger CARDMAN CONTROLLER */ > - xoutb(0x50, REG_FLAGS0(iobase)); > - > - /* Monitor progress */ > - /* wait for xmit done */ > - DEBUGP(5, dev, "Waiting for NumRecBytes getting valid\n"); > - > - for (i = 0; i < 100; i++) { > - if (inb(REG_FLAGS0(iobase)) & 0x08) { > - DEBUGP(5, dev, "NumRecBytes is valid\n"); > - break; > - } > - /* can not sleep as this is in atomic context */ > - mdelay(10); > - } > - if (i == 100) { > - DEBUGP(5, dev, "Timeout waiting for NumRecBytes getting " > - "valid\n"); > - rc = -EIO; > - goto exit_setprotocol; > - } > - > - DEBUGP(5, dev, "Reading NumRecBytes\n"); > - for (i = 0; i < 100; i++) { > - io_read_num_rec_bytes(iobase, &num_bytes_read); > - if (num_bytes_read >= 4) { > - DEBUGP(2, dev, "NumRecBytes = %i\n", num_bytes_read); > - if (num_bytes_read > 4) { > - rc = -EIO; > - goto exit_setprotocol; > - } > - break; > - } > - /* can not sleep as this is in atomic context */ > - mdelay(10); > - } > - > - /* check whether it is a short PTS reply? */ > - if (num_bytes_read == 3) > - i = 0; > - > - if (i == 100) { > - DEBUGP(5, dev, "Timeout reading num_bytes_read\n"); > - rc = -EIO; > - goto exit_setprotocol; > - } > - > - DEBUGP(5, dev, "Reset the CARDMAN CONTROLLER\n"); > - xoutb(0x80, REG_FLAGS0(iobase)); > - > - /* Read PPS reply */ > - DEBUGP(5, dev, "Read PPS reply\n"); > - for (i = 0; i < num_bytes_read; i++) { > - xoutb(i, REG_BUF_ADDR(iobase)); > - pts_reply[i] = inb(REG_BUF_DATA(iobase)); > - } > - > -#ifdef CM4000_DEBUG > - DEBUGP(2, dev, "PTSreply: "); > - for (i = 0; i < num_bytes_read; i++) { > - pr_debug("0x%.2x ", pts_reply[i]); > - } > - pr_debug("\n"); > -#endif /* CM4000_DEBUG */ > - > - DEBUGP(5, dev, "Clear Tactive in Flags1\n"); > - xoutb(0x20, REG_FLAGS1(iobase)); > - > - /* Compare ptsreq and ptsreply */ > - if ((dev->pts[0] == pts_reply[0]) && > - (dev->pts[1] == pts_reply[1]) && > - (dev->pts[2] == pts_reply[2]) && (dev->pts[3] == pts_reply[3])) { > - /* setcardparameter according to PPS */ > - dev->baudv = calc_baudv(dev->pts[2]); > - set_cardparameter(dev); > - } else if ((dev->pts[0] == pts_reply[0]) && > - ((dev->pts[1] & 0xef) == pts_reply[1]) && > - ((pts_reply[0] ^ pts_reply[1]) == pts_reply[2])) { > - /* short PTS reply, set card parameter to default values */ > - dev->baudv = calc_baudv(0x11); > - set_cardparameter(dev); > - } else > - rc = -EIO; > - > -exit_setprotocol: > - DEBUGP(3, dev, "<- set_protocol\n"); > - return rc; > -} > - > -static int io_detect_cm4000(unsigned int iobase, struct cm4000_dev *dev) > -{ > - > - /* note: statemachine is assumed to be reset */ > - if (inb(REG_FLAGS0(iobase)) & 8) { > - clear_bit(IS_ATR_VALID, &dev->flags); > - set_bit(IS_CMM_ABSENT, &dev->flags); > - return 0; /* detect CMM = 1 -> failure */ > - } > - /* xoutb(0x40, REG_FLAGS1(iobase)); detectCMM */ > - xoutb(dev->flags1 | 0x40, REG_FLAGS1(iobase)); > - if ((inb(REG_FLAGS0(iobase)) & 8) == 0) { > - clear_bit(IS_ATR_VALID, &dev->flags); > - set_bit(IS_CMM_ABSENT, &dev->flags); > - return 0; /* detect CMM=0 -> failure */ > - } > - /* clear detectCMM again by restoring original flags1 */ > - xoutb(dev->flags1, REG_FLAGS1(iobase)); > - return 1; > -} > - > -static void terminate_monitor(struct cm4000_dev *dev) > -{ > - > - /* tell the monitor to stop and wait until > - * it terminates. > - */ > - DEBUGP(3, dev, "-> terminate_monitor\n"); > - wait_event_interruptible(dev->devq, > - test_and_set_bit(LOCK_MONITOR, > - (void *)&dev->flags)); > - > - /* now, LOCK_MONITOR has been set. > - * allow a last cycle in the monitor. > - * the monitor will indicate that it has > - * finished by clearing this bit. > - */ > - DEBUGP(5, dev, "Now allow last cycle of monitor!\n"); > - while (test_bit(LOCK_MONITOR, (void *)&dev->flags)) > - msleep(25); > - > - DEBUGP(5, dev, "Delete timer\n"); > - del_timer_sync(&dev->timer); > -#ifdef CM4000_DEBUG > - dev->monitor_running = 0; > -#endif > - > - DEBUGP(3, dev, "<- terminate_monitor\n"); > -} > - > -/* > - * monitor the card every 50msec. as a side-effect, retrieve the > - * atr once a card is inserted. another side-effect of retrieving the > - * atr is that the card will be powered on, so there is no need to > - * power on the card explicitly from the application: the driver > - * is already doing that for you. > - */ > - > -static void monitor_card(struct timer_list *t) > -{ > - struct cm4000_dev *dev = from_timer(dev, t, timer); > - unsigned int iobase = dev->p_dev->resource[0]->start; > - unsigned short s; > - struct ptsreq ptsreq; > - int i, atrc; > - > - DEBUGP(7, dev, "-> monitor_card\n"); > - > - /* if someone has set the lock for us: we're done! */ > - if (test_and_set_bit(LOCK_MONITOR, &dev->flags)) { > - DEBUGP(4, dev, "About to stop monitor\n"); > - /* no */ > - dev->rlen = > - dev->rpos = > - dev->atr_csum = dev->atr_len_retry = dev->cwarn = 0; > - dev->mstate = M_FETCH_ATR; > - clear_bit(LOCK_MONITOR, &dev->flags); > - /* close et al. are sleeping on devq, so wake it */ > - wake_up_interruptible(&dev->devq); > - DEBUGP(2, dev, "<- monitor_card (we are done now)\n"); > - return; > - } > - > - /* try to lock io: if it is already locked, just add another timer */ > - if (test_and_set_bit(LOCK_IO, (void *)&dev->flags)) { > - DEBUGP(4, dev, "Couldn't get IO lock\n"); > - goto return_with_timer; > - } > - > - /* is a card/a reader inserted at all ? */ > - dev->flags0 = xinb(REG_FLAGS0(iobase)); > - DEBUGP(7, dev, "dev->flags0 = 0x%2x\n", dev->flags0); > - DEBUGP(7, dev, "smartcard present: %s\n", > - dev->flags0 & 1 ? "yes" : "no"); > - DEBUGP(7, dev, "cardman present: %s\n", > - dev->flags0 == 0xff ? "no" : "yes"); > - > - if ((dev->flags0 & 1) == 0 /* no smartcard inserted */ > - || dev->flags0 == 0xff) { /* no cardman inserted */ > - /* no */ > - dev->rlen = > - dev->rpos = > - dev->atr_csum = dev->atr_len_retry = dev->cwarn = 0; > - dev->mstate = M_FETCH_ATR; > - > - dev->flags &= 0x000000ff; /* only keep IO and MONITOR locks */ > - > - if (dev->flags0 == 0xff) { > - DEBUGP(4, dev, "set IS_CMM_ABSENT bit\n"); > - set_bit(IS_CMM_ABSENT, &dev->flags); > - } else if (test_bit(IS_CMM_ABSENT, &dev->flags)) { > - DEBUGP(4, dev, "clear IS_CMM_ABSENT bit " > - "(card is removed)\n"); > - clear_bit(IS_CMM_ABSENT, &dev->flags); > - } > - > - goto release_io; > - } else if ((dev->flags0 & 1) && test_bit(IS_CMM_ABSENT, &dev->flags)) { > - /* cardman and card present but cardman was absent before > - * (after suspend with inserted card) */ > - DEBUGP(4, dev, "clear IS_CMM_ABSENT bit (card is inserted)\n"); > - clear_bit(IS_CMM_ABSENT, &dev->flags); > - } > - > - if (test_bit(IS_ATR_VALID, &dev->flags) == 1) { > - DEBUGP(7, dev, "believe ATR is already valid (do nothing)\n"); > - goto release_io; > - } > - > - switch (dev->mstate) { > - case M_CARDOFF: { > - unsigned char flags0; > - > - DEBUGP(4, dev, "M_CARDOFF\n"); > - flags0 = inb(REG_FLAGS0(iobase)); > - if (flags0 & 0x02) { > - /* wait until Flags0 indicate power is off */ > - dev->mdelay = T_10MSEC; > - } else { > - /* Flags0 indicate power off and no card inserted now; > - * Reset CARDMAN CONTROLLER */ > - xoutb(0x80, REG_FLAGS0(iobase)); > - > - /* prepare for fetching ATR again: after card off ATR > - * is read again automatically */ > - dev->rlen = > - dev->rpos = > - dev->atr_csum = > - dev->atr_len_retry = dev->cwarn = 0; > - dev->mstate = M_FETCH_ATR; > - > - /* minimal gap between CARDOFF and read ATR is 50msec */ > - dev->mdelay = T_50MSEC; > - } > - break; > - } > - case M_FETCH_ATR: > - DEBUGP(4, dev, "M_FETCH_ATR\n"); > - xoutb(0x80, REG_FLAGS0(iobase)); > - DEBUGP(4, dev, "Reset BAUDV to 9600\n"); > - dev->baudv = 0x173; /* 9600 */ > - xoutb(0x02, REG_STOPBITS(iobase)); /* stopbits=2 */ > - xoutb(0x73, REG_BAUDRATE(iobase)); /* baud value */ > - xoutb(0x21, REG_FLAGS1(iobase)); /* T_Active=1, baud > - value */ > - /* warm start vs. power on: */ > - xoutb(dev->flags0 & 2 ? 0x46 : 0x44, REG_FLAGS0(iobase)); > - dev->mdelay = T_40MSEC; > - dev->mstate = M_TIMEOUT_WAIT; > - break; > - case M_TIMEOUT_WAIT: > - DEBUGP(4, dev, "M_TIMEOUT_WAIT\n"); > - /* numRecBytes */ > - io_read_num_rec_bytes(iobase, &dev->atr_len); > - dev->mdelay = T_10MSEC; > - dev->mstate = M_READ_ATR_LEN; > - break; > - case M_READ_ATR_LEN: > - DEBUGP(4, dev, "M_READ_ATR_LEN\n"); > - /* infinite loop possible, since there is no timeout */ > - > -#define MAX_ATR_LEN_RETRY 100 > - > - if (dev->atr_len == io_read_num_rec_bytes(iobase, &s)) { > - if (dev->atr_len_retry++ >= MAX_ATR_LEN_RETRY) { /* + XX msec */ > - dev->mdelay = T_10MSEC; > - dev->mstate = M_READ_ATR; > - } > - } else { > - dev->atr_len = s; > - dev->atr_len_retry = 0; /* set new timeout */ > - } > - > - DEBUGP(4, dev, "Current ATR_LEN = %i\n", dev->atr_len); > - break; > - case M_READ_ATR: > - DEBUGP(4, dev, "M_READ_ATR\n"); > - xoutb(0x80, REG_FLAGS0(iobase)); /* reset SM */ > - for (i = 0; i < dev->atr_len; i++) { > - xoutb(i, REG_BUF_ADDR(iobase)); > - dev->atr[i] = inb(REG_BUF_DATA(iobase)); > - } > - /* Deactivate T_Active flags */ > - DEBUGP(4, dev, "Deactivate T_Active flags\n"); > - dev->flags1 = 0x01; > - xoutb(dev->flags1, REG_FLAGS1(iobase)); > - > - /* atr is present (which doesn't mean it's valid) */ > - set_bit(IS_ATR_PRESENT, &dev->flags); > - if (dev->atr[0] == 0x03) > - str_invert_revert(dev->atr, dev->atr_len); > - atrc = parse_atr(dev); > - if (atrc == 0) { /* atr invalid */ > - dev->mdelay = 0; > - dev->mstate = M_BAD_CARD; > - } else { > - dev->mdelay = T_50MSEC; > - dev->mstate = M_ATR_PRESENT; > - set_bit(IS_ATR_VALID, &dev->flags); > - } > - > - if (test_bit(IS_ATR_VALID, &dev->flags) == 1) { > - DEBUGP(4, dev, "monitor_card: ATR valid\n"); > - /* if ta1 == 0x11, no PPS necessary (default values) */ > - /* do not do PPS with multi protocol cards */ > - if ((test_bit(IS_AUTOPPS_ACT, &dev->flags) == 0) && > - (dev->ta1 != 0x11) && > - !(test_bit(IS_ANY_T0, &dev->flags) && > - test_bit(IS_ANY_T1, &dev->flags))) { > - DEBUGP(4, dev, "Perform AUTOPPS\n"); > - set_bit(IS_AUTOPPS_ACT, &dev->flags); > - ptsreq.protocol = (0x01 << dev->proto); > - ptsreq.flags = 0x01; > - ptsreq.pts1 = 0x00; > - ptsreq.pts2 = 0x00; > - ptsreq.pts3 = 0x00; > - if (set_protocol(dev, &ptsreq) == 0) { > - DEBUGP(4, dev, "AUTOPPS ret SUCC\n"); > - clear_bit(IS_AUTOPPS_ACT, &dev->flags); > - wake_up_interruptible(&dev->atrq); > - } else { > - DEBUGP(4, dev, "AUTOPPS failed: " > - "repower using defaults\n"); > - /* prepare for repowering */ > - clear_bit(IS_ATR_PRESENT, &dev->flags); > - clear_bit(IS_ATR_VALID, &dev->flags); > - dev->rlen = > - dev->rpos = > - dev->atr_csum = > - dev->atr_len_retry = dev->cwarn = 0; > - dev->mstate = M_FETCH_ATR; > - > - dev->mdelay = T_50MSEC; > - } > - } else { > - /* for cards which use slightly different > - * params (extra guard time) */ > - set_cardparameter(dev); > - if (test_bit(IS_AUTOPPS_ACT, &dev->flags) == 1) > - DEBUGP(4, dev, "AUTOPPS already active " > - "2nd try:use default values\n"); > - if (dev->ta1 == 0x11) > - DEBUGP(4, dev, "No AUTOPPS necessary " > - "TA(1)==0x11\n"); > - if (test_bit(IS_ANY_T0, &dev->flags) > - && test_bit(IS_ANY_T1, &dev->flags)) > - DEBUGP(4, dev, "Do NOT perform AUTOPPS " > - "with multiprotocol cards\n"); > - clear_bit(IS_AUTOPPS_ACT, &dev->flags); > - wake_up_interruptible(&dev->atrq); > - } > - } else { > - DEBUGP(4, dev, "ATR invalid\n"); > - wake_up_interruptible(&dev->atrq); > - } > - break; > - case M_BAD_CARD: > - DEBUGP(4, dev, "M_BAD_CARD\n"); > - /* slow down warning, but prompt immediately after insertion */ > - if (dev->cwarn == 0 || dev->cwarn == 10) { > - set_bit(IS_BAD_CARD, &dev->flags); > - dev_warn(&dev->p_dev->dev, MODULE_NAME ": "); > - if (test_bit(IS_BAD_CSUM, &dev->flags)) { > - DEBUGP(4, dev, "ATR checksum (0x%.2x, should " > - "be zero) failed\n", dev->atr_csum); > - } > -#ifdef CM4000_DEBUG > - else if (test_bit(IS_BAD_LENGTH, &dev->flags)) { > - DEBUGP(4, dev, "ATR length error\n"); > - } else { > - DEBUGP(4, dev, "card damaged or wrong way " > - "inserted\n"); > - } > -#endif > - dev->cwarn = 0; > - wake_up_interruptible(&dev->atrq); /* wake open */ > - } > - dev->cwarn++; > - dev->mdelay = T_100MSEC; > - dev->mstate = M_FETCH_ATR; > - break; > - default: > - DEBUGP(7, dev, "Unknown action\n"); > - break; /* nothing */ > - } > - > -release_io: > - DEBUGP(7, dev, "release_io\n"); > - clear_bit(LOCK_IO, &dev->flags); > - wake_up_interruptible(&dev->ioq); /* whoever needs IO */ > - > -return_with_timer: > - DEBUGP(7, dev, "<- monitor_card (returns with timer)\n"); > - mod_timer(&dev->timer, jiffies + dev->mdelay); > - clear_bit(LOCK_MONITOR, &dev->flags); > -} > - > -/* Interface to userland (file_operations) */ > - > -static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count, > - loff_t *ppos) > -{ > - struct cm4000_dev *dev = filp->private_data; > - unsigned int iobase = dev->p_dev->resource[0]->start; > - ssize_t rc; > - int i, j, k; > - > - DEBUGP(2, dev, "-> cmm_read(%s,%d)\n", current->comm, current->pid); > - > - if (count == 0) /* according to manpage */ > - return 0; > - > - if (!pcmcia_dev_present(dev->p_dev) || /* device removed */ > - test_bit(IS_CMM_ABSENT, &dev->flags)) > - return -ENODEV; > - > - if (test_bit(IS_BAD_CSUM, &dev->flags)) > - return -EIO; > - > - /* also see the note about this in cmm_write */ > - if (wait_event_interruptible > - (dev->atrq, > - ((filp->f_flags & O_NONBLOCK) > - || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) { > - if (filp->f_flags & O_NONBLOCK) > - return -EAGAIN; > - return -ERESTARTSYS; > - } > - > - if (test_bit(IS_ATR_VALID, &dev->flags) == 0) > - return -EIO; > - > - /* this one implements blocking IO */ > - if (wait_event_interruptible > - (dev->readq, > - ((filp->f_flags & O_NONBLOCK) || (dev->rpos < dev->rlen)))) { > - if (filp->f_flags & O_NONBLOCK) > - return -EAGAIN; > - return -ERESTARTSYS; > - } > - > - /* lock io */ > - if (wait_event_interruptible > - (dev->ioq, > - ((filp->f_flags & O_NONBLOCK) > - || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) { > - if (filp->f_flags & O_NONBLOCK) > - return -EAGAIN; > - return -ERESTARTSYS; > - } > - > - rc = 0; > - dev->flags0 = inb(REG_FLAGS0(iobase)); > - if ((dev->flags0 & 1) == 0 /* no smartcard inserted */ > - || dev->flags0 == 0xff) { /* no cardman inserted */ > - clear_bit(IS_ATR_VALID, &dev->flags); > - if (dev->flags0 & 1) { > - set_bit(IS_CMM_ABSENT, &dev->flags); > - rc = -ENODEV; > - } else { > - rc = -EIO; > - } > - goto release_io; > - } > - > - DEBUGP(4, dev, "begin read answer\n"); > - j = min(count, (size_t)(dev->rlen - dev->rpos)); > - k = dev->rpos; > - if (k + j > 255) > - j = 256 - k; > - DEBUGP(4, dev, "read1 j=%d\n", j); > - for (i = 0; i < j; i++) { > - xoutb(k++, REG_BUF_ADDR(iobase)); > - dev->rbuf[i] = xinb(REG_BUF_DATA(iobase)); > - } > - j = min(count, (size_t)(dev->rlen - dev->rpos)); > - if (k + j > 255) { > - DEBUGP(4, dev, "read2 j=%d\n", j); > - dev->flags1 |= 0x10; /* MSB buf addr set */ > - xoutb(dev->flags1, REG_FLAGS1(iobase)); > - for (; i < j; i++) { > - xoutb(k++, REG_BUF_ADDR(iobase)); > - dev->rbuf[i] = xinb(REG_BUF_DATA(iobase)); > - } > - } > - > - if (dev->proto == 0 && count > dev->rlen - dev->rpos && i) { > - DEBUGP(4, dev, "T=0 and count > buffer\n"); > - dev->rbuf[i] = dev->rbuf[i - 1]; > - dev->rbuf[i - 1] = dev->procbyte; > - j++; > - } > - count = j; > - > - dev->rpos = dev->rlen + 1; > - > - /* Clear T1Active */ > - DEBUGP(4, dev, "Clear T1Active\n"); > - dev->flags1 &= 0xdf; > - xoutb(dev->flags1, REG_FLAGS1(iobase)); > - > - xoutb(0, REG_FLAGS1(iobase)); /* clear detectCMM */ > - /* last check before exit */ > - if (!io_detect_cm4000(iobase, dev)) { > - rc = -ENODEV; > - goto release_io; > - } > - > - if (test_bit(IS_INVREV, &dev->flags) && count > 0) > - str_invert_revert(dev->rbuf, count); > - > - if (copy_to_user(buf, dev->rbuf, count)) > - rc = -EFAULT; > - > -release_io: > - clear_bit(LOCK_IO, &dev->flags); > - wake_up_interruptible(&dev->ioq); > - > - DEBUGP(2, dev, "<- cmm_read returns: rc = %zi\n", > - (rc < 0 ? rc : count)); > - return rc < 0 ? rc : count; > -} > - > -static ssize_t cmm_write(struct file *filp, const char __user *buf, > - size_t count, loff_t *ppos) > -{ > - struct cm4000_dev *dev = filp->private_data; > - unsigned int iobase = dev->p_dev->resource[0]->start; > - unsigned short s; > - unsigned char infolen; > - unsigned char sendT0; > - unsigned short nsend; > - unsigned short nr; > - ssize_t rc; > - int i; > - > - DEBUGP(2, dev, "-> cmm_write(%s,%d)\n", current->comm, current->pid); > - > - if (count == 0) /* according to manpage */ > - return 0; > - > - if (dev->proto == 0 && count < 4) { > - /* T0 must have at least 4 bytes */ > - DEBUGP(4, dev, "T0 short write\n"); > - return -EIO; > - } > - > - nr = count & 0x1ff; /* max bytes to write */ > - > - sendT0 = dev->proto ? 0 : nr > 5 ? 0x08 : 0; > - > - if (!pcmcia_dev_present(dev->p_dev) || /* device removed */ > - test_bit(IS_CMM_ABSENT, &dev->flags)) > - return -ENODEV; > - > - if (test_bit(IS_BAD_CSUM, &dev->flags)) { > - DEBUGP(4, dev, "bad csum\n"); > - return -EIO; > - } > - > - /* > - * wait for atr to become valid. > - * note: it is important to lock this code. if we dont, the monitor > - * could be run between test_bit and the call to sleep on the > - * atr-queue. if *then* the monitor detects atr valid, it will wake up > - * any process on the atr-queue, *but* since we have been interrupted, > - * we do not yet sleep on this queue. this would result in a missed > - * wake_up and the calling process would sleep forever (until > - * interrupted). also, do *not* restore_flags before sleep_on, because > - * this could result in the same situation! > - */ > - if (wait_event_interruptible > - (dev->atrq, > - ((filp->f_flags & O_NONBLOCK) > - || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) { > - if (filp->f_flags & O_NONBLOCK) > - return -EAGAIN; > - return -ERESTARTSYS; > - } > - > - if (test_bit(IS_ATR_VALID, &dev->flags) == 0) { /* invalid atr */ > - DEBUGP(4, dev, "invalid ATR\n"); > - return -EIO; > - } > - > - /* lock io */ > - if (wait_event_interruptible > - (dev->ioq, > - ((filp->f_flags & O_NONBLOCK) > - || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) { > - if (filp->f_flags & O_NONBLOCK) > - return -EAGAIN; > - return -ERESTARTSYS; > - } > - > - if (copy_from_user(dev->sbuf, buf, ((count > 512) ? 512 : count))) > - return -EFAULT; > - > - rc = 0; > - dev->flags0 = inb(REG_FLAGS0(iobase)); > - if ((dev->flags0 & 1) == 0 /* no smartcard inserted */ > - || dev->flags0 == 0xff) { /* no cardman inserted */ > - clear_bit(IS_ATR_VALID, &dev->flags); > - if (dev->flags0 & 1) { > - set_bit(IS_CMM_ABSENT, &dev->flags); > - rc = -ENODEV; > - } else { > - DEBUGP(4, dev, "IO error\n"); > - rc = -EIO; > - } > - goto release_io; > - } > - > - xoutb(0x80, REG_FLAGS0(iobase)); /* reset SM */ > - > - if (!io_detect_cm4000(iobase, dev)) { > - rc = -ENODEV; > - goto release_io; > - } > - > - /* reflect T=0 send/read mode in flags1 */ > - dev->flags1 |= (sendT0); > - > - set_cardparameter(dev); > - > - /* dummy read, reset flag procedure received */ > - inb(REG_FLAGS1(iobase)); > - > - dev->flags1 = 0x20 /* T_Active */ > - | (sendT0) > - | (test_bit(IS_INVREV, &dev->flags) ? 2 : 0)/* inverse parity */ > - | (((dev->baudv - 1) & 0x0100) >> 8); /* MSB-Baud */ > - DEBUGP(1, dev, "set dev->flags1 = 0x%.2x\n", dev->flags1); > - xoutb(dev->flags1, REG_FLAGS1(iobase)); > - > - /* xmit data */ > - DEBUGP(4, dev, "Xmit data\n"); > - for (i = 0; i < nr; i++) { > - if (i >= 256) { > - dev->flags1 = 0x20 /* T_Active */ > - | (sendT0) /* SendT0 */ > - /* inverse parity: */ > - | (test_bit(IS_INVREV, &dev->flags) ? 2 : 0) > - | (((dev->baudv - 1) & 0x0100) >> 8) /* MSB-Baud */ > - | 0x10; /* set address high */ > - DEBUGP(4, dev, "dev->flags = 0x%.2x - set address " > - "high\n", dev->flags1); > - xoutb(dev->flags1, REG_FLAGS1(iobase)); > - } > - if (test_bit(IS_INVREV, &dev->flags)) { > - DEBUGP(4, dev, "Apply inverse convention for 0x%.2x " > - "-> 0x%.2x\n", (unsigned char)dev->sbuf[i], > - invert_revert(dev->sbuf[i])); > - xoutb(i, REG_BUF_ADDR(iobase)); > - xoutb(invert_revert(dev->sbuf[i]), > - REG_BUF_DATA(iobase)); > - } else { > - xoutb(i, REG_BUF_ADDR(iobase)); > - xoutb(dev->sbuf[i], REG_BUF_DATA(iobase)); > - } > - } > - DEBUGP(4, dev, "Xmit done\n"); > - > - if (dev->proto == 0) { > - /* T=0 proto: 0 byte reply */ > - if (nr == 4) { > - DEBUGP(4, dev, "T=0 assumes 0 byte reply\n"); > - xoutb(i, REG_BUF_ADDR(iobase)); > - if (test_bit(IS_INVREV, &dev->flags)) > - xoutb(0xff, REG_BUF_DATA(iobase)); > - else > - xoutb(0x00, REG_BUF_DATA(iobase)); > - } > - > - /* numSendBytes */ > - if (sendT0) > - nsend = nr; > - else { > - if (nr == 4) > - nsend = 5; > - else { > - nsend = 5 + (unsigned char)dev->sbuf[4]; > - if (dev->sbuf[4] == 0) > - nsend += 0x100; > - } > - } > - } else > - nsend = nr; > - > - /* T0: output procedure byte */ > - if (test_bit(IS_INVREV, &dev->flags)) { > - DEBUGP(4, dev, "T=0 set Procedure byte (inverse-reverse) " > - "0x%.2x\n", invert_revert(dev->sbuf[1])); > - xoutb(invert_revert(dev->sbuf[1]), REG_NUM_BYTES(iobase)); > - } else { > - DEBUGP(4, dev, "T=0 set Procedure byte 0x%.2x\n", dev->sbuf[1]); > - xoutb(dev->sbuf[1], REG_NUM_BYTES(iobase)); > - } > - > - DEBUGP(1, dev, "set NumSendBytes = 0x%.2x\n", > - (unsigned char)(nsend & 0xff)); > - xoutb((unsigned char)(nsend & 0xff), REG_NUM_SEND(iobase)); > - > - DEBUGP(1, dev, "Trigger CARDMAN CONTROLLER (0x%.2x)\n", > - 0x40 /* SM_Active */ > - | (dev->flags0 & 2 ? 0 : 4) /* power on if needed */ > - |(dev->proto ? 0x10 : 0x08) /* T=1/T=0 */ > - |(nsend & 0x100) >> 8 /* MSB numSendBytes */ ); > - xoutb(0x40 /* SM_Active */ > - | (dev->flags0 & 2 ? 0 : 4) /* power on if needed */ > - |(dev->proto ? 0x10 : 0x08) /* T=1/T=0 */ > - |(nsend & 0x100) >> 8, /* MSB numSendBytes */ > - REG_FLAGS0(iobase)); > - > - /* wait for xmit done */ > - if (dev->proto == 1) { > - DEBUGP(4, dev, "Wait for xmit done\n"); > - for (i = 0; i < 1000; i++) { > - if (inb(REG_FLAGS0(iobase)) & 0x08) > - break; > - msleep_interruptible(10); > - } > - if (i == 1000) { > - DEBUGP(4, dev, "timeout waiting for xmit done\n"); > - rc = -EIO; > - goto release_io; > - } > - } > - > - /* T=1: wait for infoLen */ > - > - infolen = 0; > - if (dev->proto) { > - /* wait until infoLen is valid */ > - for (i = 0; i < 6000; i++) { /* max waiting time of 1 min */ > - io_read_num_rec_bytes(iobase, &s); > - if (s >= 3) { > - infolen = inb(REG_FLAGS1(iobase)); > - DEBUGP(4, dev, "infolen=%d\n", infolen); > - break; > - } > - msleep_interruptible(10); > - } > - if (i == 6000) { > - DEBUGP(4, dev, "timeout waiting for infoLen\n"); > - rc = -EIO; > - goto release_io; > - } > - } else > - clear_bit(IS_PROCBYTE_PRESENT, &dev->flags); > - > - /* numRecBytes | bit9 of numRecytes */ > - io_read_num_rec_bytes(iobase, &dev->rlen); > - for (i = 0; i < 600; i++) { /* max waiting time of 2 sec */ > - if (dev->proto) { > - if (dev->rlen >= infolen + 4) > - break; > - } > - msleep_interruptible(10); > - /* numRecBytes | bit9 of numRecytes */ > - io_read_num_rec_bytes(iobase, &s); > - if (s > dev->rlen) { > - DEBUGP(1, dev, "NumRecBytes inc (reset timeout)\n"); > - i = 0; /* reset timeout */ > - dev->rlen = s; > - } > - /* T=0: we are done when numRecBytes doesn't > - * increment any more and NoProcedureByte > - * is set and numRecBytes == bytes sent + 6 > - * (header bytes + data + 1 for sw2) > - * except when the card replies an error > - * which means, no data will be sent back. > - */ > - else if (dev->proto == 0) { > - if ((inb(REG_BUF_ADDR(iobase)) & 0x80)) { > - /* no procedure byte received since last read */ > - DEBUGP(1, dev, "NoProcedure byte set\n"); > - /* i=0; */ > - } else { > - /* procedure byte received since last read */ > - DEBUGP(1, dev, "NoProcedure byte unset " > - "(reset timeout)\n"); > - dev->procbyte = inb(REG_FLAGS1(iobase)); > - DEBUGP(1, dev, "Read procedure byte 0x%.2x\n", > - dev->procbyte); > - i = 0; /* resettimeout */ > - } > - if (inb(REG_FLAGS0(iobase)) & 0x08) { > - DEBUGP(1, dev, "T0Done flag (read reply)\n"); > - break; > - } > - } > - if (dev->proto) > - infolen = inb(REG_FLAGS1(iobase)); > - } > - if (i == 600) { > - DEBUGP(1, dev, "timeout waiting for numRecBytes\n"); > - rc = -EIO; > - goto release_io; > - } else { > - if (dev->proto == 0) { > - DEBUGP(1, dev, "Wait for T0Done bit to be set\n"); > - for (i = 0; i < 1000; i++) { > - if (inb(REG_FLAGS0(iobase)) & 0x08) > - break; > - msleep_interruptible(10); > - } > - if (i == 1000) { > - DEBUGP(1, dev, "timeout waiting for T0Done\n"); > - rc = -EIO; > - goto release_io; > - } > - > - dev->procbyte = inb(REG_FLAGS1(iobase)); > - DEBUGP(4, dev, "Read procedure byte 0x%.2x\n", > - dev->procbyte); > - > - io_read_num_rec_bytes(iobase, &dev->rlen); > - DEBUGP(4, dev, "Read NumRecBytes = %i\n", dev->rlen); > - > - } > - } > - /* T=1: read offset=zero, T=0: read offset=after challenge */ > - dev->rpos = dev->proto ? 0 : nr == 4 ? 5 : nr > dev->rlen ? 5 : nr; > - DEBUGP(4, dev, "dev->rlen = %i, dev->rpos = %i, nr = %i\n", > - dev->rlen, dev->rpos, nr); > - > -release_io: > - DEBUGP(4, dev, "Reset SM\n"); > - xoutb(0x80, REG_FLAGS0(iobase)); /* reset SM */ > - > - if (rc < 0) { > - DEBUGP(4, dev, "Write failed but clear T_Active\n"); > - dev->flags1 &= 0xdf; > - xoutb(dev->flags1, REG_FLAGS1(iobase)); > - } > - > - clear_bit(LOCK_IO, &dev->flags); > - wake_up_interruptible(&dev->ioq); > - wake_up_interruptible(&dev->readq); /* tell read we have data */ > - > - /* ITSEC E2: clear write buffer */ > - memset((char *)dev->sbuf, 0, 512); > - > - /* return error or actually written bytes */ > - DEBUGP(2, dev, "<- cmm_write\n"); > - return rc < 0 ? rc : nr; > -} > - > -static void start_monitor(struct cm4000_dev *dev) > -{ > - DEBUGP(3, dev, "-> start_monitor\n"); > - if (!dev->monitor_running) { > - DEBUGP(5, dev, "create, init and add timer\n"); > - timer_setup(&dev->timer, monitor_card, 0); > - dev->monitor_running = 1; > - mod_timer(&dev->timer, jiffies); > - } else > - DEBUGP(5, dev, "monitor already running\n"); > - DEBUGP(3, dev, "<- start_monitor\n"); > -} > - > -static void stop_monitor(struct cm4000_dev *dev) > -{ > - DEBUGP(3, dev, "-> stop_monitor\n"); > - if (dev->monitor_running) { > - DEBUGP(5, dev, "stopping monitor\n"); > - terminate_monitor(dev); > - /* reset monitor SM */ > - clear_bit(IS_ATR_VALID, &dev->flags); > - clear_bit(IS_ATR_PRESENT, &dev->flags); > - } else > - DEBUGP(5, dev, "monitor already stopped\n"); > - DEBUGP(3, dev, "<- stop_monitor\n"); > -} > - > -static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) > -{ > - struct cm4000_dev *dev = filp->private_data; > - unsigned int iobase = dev->p_dev->resource[0]->start; > - struct inode *inode = file_inode(filp); > - struct pcmcia_device *link; > - int rc; > - void __user *argp = (void __user *)arg; > -#ifdef CM4000_DEBUG > - char *ioctl_names[CM_IOC_MAXNR + 1] = { > - [_IOC_NR(CM_IOCGSTATUS)] "CM_IOCGSTATUS", > - [_IOC_NR(CM_IOCGATR)] "CM_IOCGATR", > - [_IOC_NR(CM_IOCARDOFF)] "CM_IOCARDOFF", > - [_IOC_NR(CM_IOCSPTS)] "CM_IOCSPTS", > - [_IOC_NR(CM_IOSDBGLVL)] "CM4000_DBGLVL", > - }; > - DEBUGP(3, dev, "cmm_ioctl(device=%d.%d) %s\n", imajor(inode), > - iminor(inode), ioctl_names[_IOC_NR(cmd)]); > -#endif > - > - mutex_lock(&cmm_mutex); > - rc = -ENODEV; > - link = dev_table[iminor(inode)]; > - if (!pcmcia_dev_present(link)) { > - DEBUGP(4, dev, "DEV_OK false\n"); > - goto out; > - } > - > - if (test_bit(IS_CMM_ABSENT, &dev->flags)) { > - DEBUGP(4, dev, "CMM_ABSENT flag set\n"); > - goto out; > - } > - rc = -EINVAL; > - > - if (_IOC_TYPE(cmd) != CM_IOC_MAGIC) { > - DEBUGP(4, dev, "ioctype mismatch\n"); > - goto out; > - } > - if (_IOC_NR(cmd) > CM_IOC_MAXNR) { > - DEBUGP(4, dev, "iocnr mismatch\n"); > - goto out; > - } > - rc = 0; > - > - switch (cmd) { > - case CM_IOCGSTATUS: > - DEBUGP(4, dev, " ... in CM_IOCGSTATUS\n"); > - { > - int status; > - > - /* clear other bits, but leave inserted & powered as > - * they are */ > - status = dev->flags0 & 3; > - if (test_bit(IS_ATR_PRESENT, &dev->flags)) > - status |= CM_ATR_PRESENT; > - if (test_bit(IS_ATR_VALID, &dev->flags)) > - status |= CM_ATR_VALID; > - if (test_bit(IS_CMM_ABSENT, &dev->flags)) > - status |= CM_NO_READER; > - if (test_bit(IS_BAD_CARD, &dev->flags)) > - status |= CM_BAD_CARD; > - if (copy_to_user(argp, &status, sizeof(int))) > - rc = -EFAULT; > - } > - break; > - case CM_IOCGATR: > - DEBUGP(4, dev, "... in CM_IOCGATR\n"); > - { > - struct atreq __user *atreq = argp; > - int tmp; > - /* allow nonblocking io and being interrupted */ > - if (wait_event_interruptible > - (dev->atrq, > - ((filp->f_flags & O_NONBLOCK) > - || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) > - != 0)))) { > - if (filp->f_flags & O_NONBLOCK) > - rc = -EAGAIN; > - else > - rc = -ERESTARTSYS; > - break; > - } > - > - rc = -EFAULT; > - if (test_bit(IS_ATR_VALID, &dev->flags) == 0) { > - tmp = -1; > - if (copy_to_user(&(atreq->atr_len), &tmp, > - sizeof(int))) > - break; > - } else { > - if (copy_to_user(atreq->atr, dev->atr, > - dev->atr_len)) > - break; > - > - tmp = dev->atr_len; > - if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int))) > - break; > - } > - rc = 0; > - break; > - } > - case CM_IOCARDOFF: > - > -#ifdef CM4000_DEBUG > - DEBUGP(4, dev, "... in CM_IOCARDOFF\n"); > - if (dev->flags0 & 0x01) { > - DEBUGP(4, dev, " Card inserted\n"); > - } else { > - DEBUGP(2, dev, " No card inserted\n"); > - } > - if (dev->flags0 & 0x02) { > - DEBUGP(4, dev, " Card powered\n"); > - } else { > - DEBUGP(2, dev, " Card not powered\n"); > - } > -#endif > - > - /* is a card inserted and powered? */ > - if ((dev->flags0 & 0x01) && (dev->flags0 & 0x02)) { > - > - /* get IO lock */ > - if (wait_event_interruptible > - (dev->ioq, > - ((filp->f_flags & O_NONBLOCK) > - || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) > - == 0)))) { > - if (filp->f_flags & O_NONBLOCK) > - rc = -EAGAIN; > - else > - rc = -ERESTARTSYS; > - break; > - } > - /* Set Flags0 = 0x42 */ > - DEBUGP(4, dev, "Set Flags0=0x42 \n"); > - xoutb(0x42, REG_FLAGS0(iobase)); > - clear_bit(IS_ATR_PRESENT, &dev->flags); > - clear_bit(IS_ATR_VALID, &dev->flags); > - dev->mstate = M_CARDOFF; > - clear_bit(LOCK_IO, &dev->flags); > - if (wait_event_interruptible > - (dev->atrq, > - ((filp->f_flags & O_NONBLOCK) > - || (test_bit(IS_ATR_VALID, (void *)&dev->flags) != > - 0)))) { > - if (filp->f_flags & O_NONBLOCK) > - rc = -EAGAIN; > - else > - rc = -ERESTARTSYS; > - break; > - } > - } > - /* release lock */ > - clear_bit(LOCK_IO, &dev->flags); > - wake_up_interruptible(&dev->ioq); > - > - rc = 0; > - break; > - case CM_IOCSPTS: > - { > - struct ptsreq krnptsreq; > - > - if (copy_from_user(&krnptsreq, argp, > - sizeof(struct ptsreq))) { > - rc = -EFAULT; > - break; > - } > - > - rc = 0; > - DEBUGP(4, dev, "... in CM_IOCSPTS\n"); > - /* wait for ATR to get valid */ > - if (wait_event_interruptible > - (dev->atrq, > - ((filp->f_flags & O_NONBLOCK) > - || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) > - != 0)))) { > - if (filp->f_flags & O_NONBLOCK) > - rc = -EAGAIN; > - else > - rc = -ERESTARTSYS; > - break; > - } > - /* get IO lock */ > - if (wait_event_interruptible > - (dev->ioq, > - ((filp->f_flags & O_NONBLOCK) > - || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) > - == 0)))) { > - if (filp->f_flags & O_NONBLOCK) > - rc = -EAGAIN; > - else > - rc = -ERESTARTSYS; > - break; > - } > - > - if ((rc = set_protocol(dev, &krnptsreq)) != 0) { > - /* auto power_on again */ > - dev->mstate = M_FETCH_ATR; > - clear_bit(IS_ATR_VALID, &dev->flags); > - } > - /* release lock */ > - clear_bit(LOCK_IO, &dev->flags); > - wake_up_interruptible(&dev->ioq); > - > - } > - break; > -#ifdef CM4000_DEBUG > - case CM_IOSDBGLVL: > - rc = -ENOTTY; > - break; > -#endif > - default: > - DEBUGP(4, dev, "... in default (unknown IOCTL code)\n"); > - rc = -ENOTTY; > - } > -out: > - mutex_unlock(&cmm_mutex); > - return rc; > -} > - > -static int cmm_open(struct inode *inode, struct file *filp) > -{ > - struct cm4000_dev *dev; > - struct pcmcia_device *link; > - int minor = iminor(inode); > - int ret; > - > - if (minor >= CM4000_MAX_DEV) > - return -ENODEV; > - > - mutex_lock(&cmm_mutex); > - link = dev_table[minor]; > - if (link == NULL || !pcmcia_dev_present(link)) { > - ret = -ENODEV; > - goto out; > - } > - > - if (link->open) { > - ret = -EBUSY; > - goto out; > - } > - > - dev = link->priv; > - filp->private_data = dev; > - > - DEBUGP(2, dev, "-> cmm_open(device=%d.%d process=%s,%d)\n", > - imajor(inode), minor, current->comm, current->pid); > - > - /* init device variables, they may be "polluted" after close > - * or, the device may never have been closed (i.e. open failed) > - */ > - > - ZERO_DEV(dev); > - > - /* opening will always block since the > - * monitor will be started by open, which > - * means we have to wait for ATR becoming > - * valid = block until valid (or card > - * inserted) > - */ > - if (filp->f_flags & O_NONBLOCK) { > - ret = -EAGAIN; > - goto out; > - } > - > - dev->mdelay = T_50MSEC; > - > - /* start monitoring the cardstatus */ > - start_monitor(dev); > - > - link->open = 1; /* only one open per device */ > - > - DEBUGP(2, dev, "<- cmm_open\n"); > - ret = stream_open(inode, filp); > -out: > - mutex_unlock(&cmm_mutex); > - return ret; > -} > - > -static int cmm_close(struct inode *inode, struct file *filp) > -{ > - struct cm4000_dev *dev; > - struct pcmcia_device *link; > - int minor = iminor(inode); > - > - if (minor >= CM4000_MAX_DEV) > - return -ENODEV; > - > - link = dev_table[minor]; > - if (link == NULL) > - return -ENODEV; > - > - dev = link->priv; > - > - DEBUGP(2, dev, "-> cmm_close(maj/min=%d.%d)\n", > - imajor(inode), minor); > - > - stop_monitor(dev); > - > - ZERO_DEV(dev); > - > - link->open = 0; /* only one open per device */ > - wake_up(&dev->devq); /* socket removed? */ > - > - DEBUGP(2, dev, "cmm_close\n"); > - return 0; > -} > - > -static void cmm_cm4000_release(struct pcmcia_device * link) > -{ > - struct cm4000_dev *dev = link->priv; > - > - /* dont terminate the monitor, rather rely on > - * close doing that for us. > - */ > - DEBUGP(3, dev, "-> cmm_cm4000_release\n"); > - while (link->open) { > - printk(KERN_INFO MODULE_NAME ": delaying release until " > - "process has terminated\n"); > - /* note: don't interrupt us: > - * close the applications which own > - * the devices _first_ ! > - */ > - wait_event(dev->devq, (link->open == 0)); > - } > - /* dev->devq=NULL; this cannot be zeroed earlier */ > - DEBUGP(3, dev, "<- cmm_cm4000_release\n"); > - return; > -} > - > -/*==== Interface to PCMCIA Layer =======================================*/ > - > -static int cm4000_config_check(struct pcmcia_device *p_dev, void *priv_data) > -{ > - return pcmcia_request_io(p_dev); > -} > - > -static int cm4000_config(struct pcmcia_device * link, int devno) > -{ > - link->config_flags |= CONF_AUTO_SET_IO; > - > - /* read the config-tuples */ > - if (pcmcia_loop_config(link, cm4000_config_check, NULL)) > - goto cs_release; > - > - if (pcmcia_enable_device(link)) > - goto cs_release; > - > - return 0; > - > -cs_release: > - cm4000_release(link); > - return -ENODEV; > -} > - > -static int cm4000_suspend(struct pcmcia_device *link) > -{ > - struct cm4000_dev *dev; > - > - dev = link->priv; > - stop_monitor(dev); > - > - return 0; > -} > - > -static int cm4000_resume(struct pcmcia_device *link) > -{ > - struct cm4000_dev *dev; > - > - dev = link->priv; > - if (link->open) > - start_monitor(dev); > - > - return 0; > -} > - > -static void cm4000_release(struct pcmcia_device *link) > -{ > - cmm_cm4000_release(link); /* delay release until device closed */ > - pcmcia_disable_device(link); > -} > - > -static int cm4000_probe(struct pcmcia_device *link) > -{ > - struct cm4000_dev *dev; > - int i, ret; > - > - for (i = 0; i < CM4000_MAX_DEV; i++) > - if (dev_table[i] == NULL) > - break; > - > - if (i == CM4000_MAX_DEV) { > - printk(KERN_NOTICE MODULE_NAME ": all devices in use\n"); > - return -ENODEV; > - } > - > - /* create a new cm4000_cs device */ > - dev = kzalloc(sizeof(struct cm4000_dev), GFP_KERNEL); > - if (dev == NULL) > - return -ENOMEM; > - > - dev->p_dev = link; > - link->priv = dev; > - dev_table[i] = link; > - > - init_waitqueue_head(&dev->devq); > - init_waitqueue_head(&dev->ioq); > - init_waitqueue_head(&dev->atrq); > - init_waitqueue_head(&dev->readq); > - > - ret = cm4000_config(link, i); > - if (ret) { > - dev_table[i] = NULL; > - kfree(dev); > - return ret; > - } > - > - device_create(cmm_class, NULL, MKDEV(major, i), NULL, "cmm%d", i); > - > - return 0; > -} > - > -static void cm4000_detach(struct pcmcia_device *link) > -{ > - struct cm4000_dev *dev = link->priv; > - int devno; > - > - /* find device */ > - for (devno = 0; devno < CM4000_MAX_DEV; devno++) > - if (dev_table[devno] == link) > - break; > - if (devno == CM4000_MAX_DEV) > - return; > - > - stop_monitor(dev); > - > - cm4000_release(link); > - > - dev_table[devno] = NULL; > - kfree(dev); > - > - device_destroy(cmm_class, MKDEV(major, devno)); > - > - return; > -} > - > -static const struct file_operations cm4000_fops = { > - .owner = THIS_MODULE, > - .read = cmm_read, > - .write = cmm_write, > - .unlocked_ioctl = cmm_ioctl, > - .open = cmm_open, > - .release= cmm_close, > - .llseek = no_llseek, > -}; > - > -static const struct pcmcia_device_id cm4000_ids[] = { > - PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0002), > - PCMCIA_DEVICE_PROD_ID12("CardMan", "4000", 0x2FB368CA, 0xA2BD8C39), > - PCMCIA_DEVICE_NULL, > -}; > -MODULE_DEVICE_TABLE(pcmcia, cm4000_ids); > - > -static struct pcmcia_driver cm4000_driver = { > - .owner = THIS_MODULE, > - .name = "cm4000_cs", > - .probe = cm4000_probe, > - .remove = cm4000_detach, > - .suspend = cm4000_suspend, > - .resume = cm4000_resume, > - .id_table = cm4000_ids, > -}; > - > -static int __init cmm_init(void) > -{ > - int rc; > - > - cmm_class = class_create(THIS_MODULE, "cardman_4000"); > - if (IS_ERR(cmm_class)) > - return PTR_ERR(cmm_class); > - > - major = register_chrdev(0, DEVICE_NAME, &cm4000_fops); > - if (major < 0) { > - printk(KERN_WARNING MODULE_NAME > - ": could not get major number\n"); > - class_destroy(cmm_class); > - return major; > - } > - > - rc = pcmcia_register_driver(&cm4000_driver); > - if (rc < 0) { > - unregister_chrdev(major, DEVICE_NAME); > - class_destroy(cmm_class); > - return rc; > - } > - > - return 0; > -} > - > -static void __exit cmm_exit(void) > -{ > - pcmcia_unregister_driver(&cm4000_driver); > - unregister_chrdev(major, DEVICE_NAME); > - class_destroy(cmm_class); > -}; > - > -module_init(cmm_init); > -module_exit(cmm_exit); > -MODULE_LICENSE("Dual BSD/GPL"); > diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c > deleted file mode 100644 > index 827711911da4..000000000000 > --- a/drivers/char/pcmcia/cm4040_cs.c > +++ /dev/null > @@ -1,684 +0,0 @@ > -/* > - * A driver for the Omnikey PCMCIA smartcard reader CardMan 4040 > - * > - * (c) 2000-2004 Omnikey AG (http://www.omnikey.com/) > - * > - * (C) 2005-2006 Harald Welte > - * - add support for poll() > - * - driver cleanup > - * - add waitqueues > - * - adhere to linux kernel coding style and policies > - * - support 2.6.13 "new style" pcmcia interface > - * - add class interface for udev device creation > - * > - * The device basically is a USB CCID compliant device that has been > - * attached to an I/O-Mapped FIFO. > - * > - * All rights reserved, Dual BSD/GPL Licensed. > - */ > - > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > - > -#include > -#include > -#include > -#include > - > -#include "cm4040_cs.h" > - > - > -#define reader_to_dev(x) (&x->p_dev->dev) > - > -/* n (debug level) is ignored */ > -/* additional debug output may be enabled by re-compiling with > - * CM4040_DEBUG set */ > -/* #define CM4040_DEBUG */ > -#define DEBUGP(n, rdr, x, args...) do { \ > - dev_dbg(reader_to_dev(rdr), "%s:" x, \ > - __func__ , ## args); \ > - } while (0) > - > -static DEFINE_MUTEX(cm4040_mutex); > - > -#define CCID_DRIVER_BULK_DEFAULT_TIMEOUT (150*HZ) > -#define CCID_DRIVER_ASYNC_POWERUP_TIMEOUT (35*HZ) > -#define CCID_DRIVER_MINIMUM_TIMEOUT (3*HZ) > -#define READ_WRITE_BUFFER_SIZE 512 > -#define POLL_LOOP_COUNT 1000 > - > -/* how often to poll for fifo status change */ > -#define POLL_PERIOD msecs_to_jiffies(10) > - > -static void reader_release(struct pcmcia_device *link); > - > -static int major; > -static struct class *cmx_class; > - > -#define BS_READABLE 0x01 > -#define BS_WRITABLE 0x02 > - > -struct reader_dev { > - struct pcmcia_device *p_dev; > - wait_queue_head_t devq; > - wait_queue_head_t poll_wait; > - wait_queue_head_t read_wait; > - wait_queue_head_t write_wait; > - unsigned long buffer_status; > - unsigned long timeout; > - unsigned char s_buf[READ_WRITE_BUFFER_SIZE]; > - unsigned char r_buf[READ_WRITE_BUFFER_SIZE]; > - struct timer_list poll_timer; > -}; > - > -static struct pcmcia_device *dev_table[CM_MAX_DEV]; > - > -#ifndef CM4040_DEBUG > -#define xoutb outb > -#define xinb inb > -#else > -static inline void xoutb(unsigned char val, unsigned short port) > -{ > - pr_debug("outb(val=%.2x,port=%.4x)\n", val, port); > - outb(val, port); > -} > - > -static inline unsigned char xinb(unsigned short port) > -{ > - unsigned char val; > - > - val = inb(port); > - pr_debug("%.2x=inb(%.4x)\n", val, port); > - return val; > -} > -#endif > - > -/* poll the device fifo status register. not to be confused with > - * the poll syscall. */ > -static void cm4040_do_poll(struct timer_list *t) > -{ > - struct reader_dev *dev = from_timer(dev, t, poll_timer); > - unsigned int obs = xinb(dev->p_dev->resource[0]->start > - + REG_OFFSET_BUFFER_STATUS); > - > - if ((obs & BSR_BULK_IN_FULL)) { > - set_bit(BS_READABLE, &dev->buffer_status); > - DEBUGP(4, dev, "waking up read_wait\n"); > - wake_up_interruptible(&dev->read_wait); > - } else > - clear_bit(BS_READABLE, &dev->buffer_status); > - > - if (!(obs & BSR_BULK_OUT_FULL)) { > - set_bit(BS_WRITABLE, &dev->buffer_status); > - DEBUGP(4, dev, "waking up write_wait\n"); > - wake_up_interruptible(&dev->write_wait); > - } else > - clear_bit(BS_WRITABLE, &dev->buffer_status); > - > - if (dev->buffer_status) > - wake_up_interruptible(&dev->poll_wait); > - > - mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD); > -} > - > -static void cm4040_stop_poll(struct reader_dev *dev) > -{ > - del_timer_sync(&dev->poll_timer); > -} > - > -static int wait_for_bulk_out_ready(struct reader_dev *dev) > -{ > - int i, rc; > - int iobase = dev->p_dev->resource[0]->start; > - > - for (i = 0; i < POLL_LOOP_COUNT; i++) { > - if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS) > - & BSR_BULK_OUT_FULL) == 0) { > - DEBUGP(4, dev, "BulkOut empty (i=%d)\n", i); > - return 1; > - } > - } > - > - DEBUGP(4, dev, "wait_event_interruptible_timeout(timeout=%ld\n", > - dev->timeout); > - rc = wait_event_interruptible_timeout(dev->write_wait, > - test_and_clear_bit(BS_WRITABLE, > - &dev->buffer_status), > - dev->timeout); > - > - if (rc > 0) > - DEBUGP(4, dev, "woke up: BulkOut empty\n"); > - else if (rc == 0) > - DEBUGP(4, dev, "woke up: BulkOut full, returning 0 :(\n"); > - else if (rc < 0) > - DEBUGP(4, dev, "woke up: signal arrived\n"); > - > - return rc; > -} > - > -/* Write to Sync Control Register */ > -static int write_sync_reg(unsigned char val, struct reader_dev *dev) > -{ > - int iobase = dev->p_dev->resource[0]->start; > - int rc; > - > - rc = wait_for_bulk_out_ready(dev); > - if (rc <= 0) > - return rc; > - > - xoutb(val, iobase + REG_OFFSET_SYNC_CONTROL); > - rc = wait_for_bulk_out_ready(dev); > - if (rc <= 0) > - return rc; > - > - return 1; > -} > - > -static int wait_for_bulk_in_ready(struct reader_dev *dev) > -{ > - int i, rc; > - int iobase = dev->p_dev->resource[0]->start; > - > - for (i = 0; i < POLL_LOOP_COUNT; i++) { > - if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS) > - & BSR_BULK_IN_FULL) == BSR_BULK_IN_FULL) { > - DEBUGP(3, dev, "BulkIn full (i=%d)\n", i); > - return 1; > - } > - } > - > - DEBUGP(4, dev, "wait_event_interruptible_timeout(timeout=%ld\n", > - dev->timeout); > - rc = wait_event_interruptible_timeout(dev->read_wait, > - test_and_clear_bit(BS_READABLE, > - &dev->buffer_status), > - dev->timeout); > - if (rc > 0) > - DEBUGP(4, dev, "woke up: BulkIn full\n"); > - else if (rc == 0) > - DEBUGP(4, dev, "woke up: BulkIn not full, returning 0 :(\n"); > - else if (rc < 0) > - DEBUGP(4, dev, "woke up: signal arrived\n"); > - > - return rc; > -} > - > -static ssize_t cm4040_read(struct file *filp, char __user *buf, > - size_t count, loff_t *ppos) > -{ > - struct reader_dev *dev = filp->private_data; > - int iobase = dev->p_dev->resource[0]->start; > - size_t bytes_to_read; > - unsigned long i; > - size_t min_bytes_to_read; > - int rc; > - > - DEBUGP(2, dev, "-> cm4040_read(%s,%d)\n", current->comm, current->pid); > - > - if (count == 0) > - return 0; > - > - if (count < 10) > - return -EFAULT; > - > - if (filp->f_flags & O_NONBLOCK) { > - DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n"); > - DEBUGP(2, dev, "<- cm4040_read (failure)\n"); > - return -EAGAIN; > - } > - > - if (!pcmcia_dev_present(dev->p_dev)) > - return -ENODEV; > - > - for (i = 0; i < 5; i++) { > - rc = wait_for_bulk_in_ready(dev); > - if (rc <= 0) { > - DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc); > - DEBUGP(2, dev, "<- cm4040_read (failed)\n"); > - if (rc == -ERESTARTSYS) > - return rc; > - return -EIO; > - } > - dev->r_buf[i] = xinb(iobase + REG_OFFSET_BULK_IN); > -#ifdef CM4040_DEBUG > - pr_debug("%lu:%2x ", i, dev->r_buf[i]); > - } > - pr_debug("\n"); > -#else > - } > -#endif > - > - bytes_to_read = 5 + le32_to_cpu(*(__le32 *)&dev->r_buf[1]); > - > - DEBUGP(6, dev, "BytesToRead=%zu\n", bytes_to_read); > - > - min_bytes_to_read = min(count, bytes_to_read + 5); > - min_bytes_to_read = min_t(size_t, min_bytes_to_read, READ_WRITE_BUFFER_SIZE); > - > - DEBUGP(6, dev, "Min=%zu\n", min_bytes_to_read); > - > - for (i = 0; i < (min_bytes_to_read-5); i++) { > - rc = wait_for_bulk_in_ready(dev); > - if (rc <= 0) { > - DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc); > - DEBUGP(2, dev, "<- cm4040_read (failed)\n"); > - if (rc == -ERESTARTSYS) > - return rc; > - return -EIO; > - } > - dev->r_buf[i+5] = xinb(iobase + REG_OFFSET_BULK_IN); > -#ifdef CM4040_DEBUG > - pr_debug("%lu:%2x ", i, dev->r_buf[i]); > - } > - pr_debug("\n"); > -#else > - } > -#endif > - > - *ppos = min_bytes_to_read; > - if (copy_to_user(buf, dev->r_buf, min_bytes_to_read)) > - return -EFAULT; > - > - rc = wait_for_bulk_in_ready(dev); > - if (rc <= 0) { > - DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc); > - DEBUGP(2, dev, "<- cm4040_read (failed)\n"); > - if (rc == -ERESTARTSYS) > - return rc; > - return -EIO; > - } > - > - rc = write_sync_reg(SCR_READER_TO_HOST_DONE, dev); > - if (rc <= 0) { > - DEBUGP(5, dev, "write_sync_reg c=%.2x\n", rc); > - DEBUGP(2, dev, "<- cm4040_read (failed)\n"); > - if (rc == -ERESTARTSYS) > - return rc; > - else > - return -EIO; > - } > - > - xinb(iobase + REG_OFFSET_BULK_IN); > - > - DEBUGP(2, dev, "<- cm4040_read (successfully)\n"); > - return min_bytes_to_read; > -} > - > -static ssize_t cm4040_write(struct file *filp, const char __user *buf, > - size_t count, loff_t *ppos) > -{ > - struct reader_dev *dev = filp->private_data; > - int iobase = dev->p_dev->resource[0]->start; > - ssize_t rc; > - int i; > - unsigned int bytes_to_write; > - > - DEBUGP(2, dev, "-> cm4040_write(%s,%d)\n", current->comm, current->pid); > - > - if (count == 0) { > - DEBUGP(2, dev, "<- cm4040_write empty read (successfully)\n"); > - return 0; > - } > - > - if ((count < 5) || (count > READ_WRITE_BUFFER_SIZE)) { > - DEBUGP(2, dev, "<- cm4040_write buffersize=%zd < 5\n", count); > - return -EIO; > - } > - > - if (filp->f_flags & O_NONBLOCK) { > - DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n"); > - DEBUGP(4, dev, "<- cm4040_write (failure)\n"); > - return -EAGAIN; > - } > - > - if (!pcmcia_dev_present(dev->p_dev)) > - return -ENODEV; > - > - bytes_to_write = count; > - if (copy_from_user(dev->s_buf, buf, bytes_to_write)) > - return -EFAULT; > - > - switch (dev->s_buf[0]) { > - case CMD_PC_TO_RDR_XFRBLOCK: > - case CMD_PC_TO_RDR_SECURE: > - case CMD_PC_TO_RDR_TEST_SECURE: > - case CMD_PC_TO_RDR_OK_SECURE: > - dev->timeout = CCID_DRIVER_BULK_DEFAULT_TIMEOUT; > - break; > - > - case CMD_PC_TO_RDR_ICCPOWERON: > - dev->timeout = CCID_DRIVER_ASYNC_POWERUP_TIMEOUT; > - break; > - > - case CMD_PC_TO_RDR_GETSLOTSTATUS: > - case CMD_PC_TO_RDR_ICCPOWEROFF: > - case CMD_PC_TO_RDR_GETPARAMETERS: > - case CMD_PC_TO_RDR_RESETPARAMETERS: > - case CMD_PC_TO_RDR_SETPARAMETERS: > - case CMD_PC_TO_RDR_ESCAPE: > - case CMD_PC_TO_RDR_ICCCLOCK: > - default: > - dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT; > - break; > - } > - > - rc = write_sync_reg(SCR_HOST_TO_READER_START, dev); > - if (rc <= 0) { > - DEBUGP(5, dev, "write_sync_reg c=%.2zx\n", rc); > - DEBUGP(2, dev, "<- cm4040_write (failed)\n"); > - if (rc == -ERESTARTSYS) > - return rc; > - else > - return -EIO; > - } > - > - DEBUGP(4, dev, "start \n"); > - > - for (i = 0; i < bytes_to_write; i++) { > - rc = wait_for_bulk_out_ready(dev); > - if (rc <= 0) { > - DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2zx\n", > - rc); > - DEBUGP(2, dev, "<- cm4040_write (failed)\n"); > - if (rc == -ERESTARTSYS) > - return rc; > - else > - return -EIO; > - } > - > - xoutb(dev->s_buf[i],iobase + REG_OFFSET_BULK_OUT); > - } > - DEBUGP(4, dev, "end\n"); > - > - rc = write_sync_reg(SCR_HOST_TO_READER_DONE, dev); > - > - if (rc <= 0) { > - DEBUGP(5, dev, "write_sync_reg c=%.2zx\n", rc); > - DEBUGP(2, dev, "<- cm4040_write (failed)\n"); > - if (rc == -ERESTARTSYS) > - return rc; > - else > - return -EIO; > - } > - > - DEBUGP(2, dev, "<- cm4040_write (successfully)\n"); > - return count; > -} > - > -static __poll_t cm4040_poll(struct file *filp, poll_table *wait) > -{ > - struct reader_dev *dev = filp->private_data; > - __poll_t mask = 0; > - > - poll_wait(filp, &dev->poll_wait, wait); > - > - if (test_and_clear_bit(BS_READABLE, &dev->buffer_status)) > - mask |= EPOLLIN | EPOLLRDNORM; > - if (test_and_clear_bit(BS_WRITABLE, &dev->buffer_status)) > - mask |= EPOLLOUT | EPOLLWRNORM; > - > - DEBUGP(2, dev, "<- cm4040_poll(%u)\n", mask); > - > - return mask; > -} > - > -static int cm4040_open(struct inode *inode, struct file *filp) > -{ > - struct reader_dev *dev; > - struct pcmcia_device *link; > - int minor = iminor(inode); > - int ret; > - > - if (minor >= CM_MAX_DEV) > - return -ENODEV; > - > - mutex_lock(&cm4040_mutex); > - link = dev_table[minor]; > - if (link == NULL || !pcmcia_dev_present(link)) { > - ret = -ENODEV; > - goto out; > - } > - > - if (link->open) { > - ret = -EBUSY; > - goto out; > - } > - > - dev = link->priv; > - filp->private_data = dev; > - > - if (filp->f_flags & O_NONBLOCK) { > - DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n"); > - ret = -EAGAIN; > - goto out; > - } > - > - link->open = 1; > - > - mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD); > - > - DEBUGP(2, dev, "<- cm4040_open (successfully)\n"); > - ret = nonseekable_open(inode, filp); > -out: > - mutex_unlock(&cm4040_mutex); > - return ret; > -} > - > -static int cm4040_close(struct inode *inode, struct file *filp) > -{ > - struct reader_dev *dev = filp->private_data; > - struct pcmcia_device *link; > - int minor = iminor(inode); > - > - DEBUGP(2, dev, "-> cm4040_close(maj/min=%d.%d)\n", imajor(inode), > - iminor(inode)); > - > - if (minor >= CM_MAX_DEV) > - return -ENODEV; > - > - link = dev_table[minor]; > - if (link == NULL) > - return -ENODEV; > - > - cm4040_stop_poll(dev); > - > - link->open = 0; > - wake_up(&dev->devq); > - > - DEBUGP(2, dev, "<- cm4040_close\n"); > - return 0; > -} > - > -static void cm4040_reader_release(struct pcmcia_device *link) > -{ > - struct reader_dev *dev = link->priv; > - > - DEBUGP(3, dev, "-> cm4040_reader_release\n"); > - while (link->open) { > - DEBUGP(3, dev, MODULE_NAME ": delaying release " > - "until process has terminated\n"); > - wait_event(dev->devq, (link->open == 0)); > - } > - DEBUGP(3, dev, "<- cm4040_reader_release\n"); > - return; > -} > - > -static int cm4040_config_check(struct pcmcia_device *p_dev, void *priv_data) > -{ > - return pcmcia_request_io(p_dev); > -} > - > - > -static int reader_config(struct pcmcia_device *link, int devno) > -{ > - struct reader_dev *dev; > - int fail_rc; > - > - link->config_flags |= CONF_AUTO_SET_IO; > - > - if (pcmcia_loop_config(link, cm4040_config_check, NULL)) > - goto cs_release; > - > - fail_rc = pcmcia_enable_device(link); > - if (fail_rc != 0) { > - dev_info(&link->dev, "pcmcia_enable_device failed 0x%x\n", > - fail_rc); > - goto cs_release; > - } > - > - dev = link->priv; > - > - DEBUGP(2, dev, "device " DEVICE_NAME "%d at %pR\n", devno, > - link->resource[0]); > - DEBUGP(2, dev, "<- reader_config (succ)\n"); > - > - return 0; > - > -cs_release: > - reader_release(link); > - return -ENODEV; > -} > - > -static void reader_release(struct pcmcia_device *link) > -{ > - cm4040_reader_release(link); > - pcmcia_disable_device(link); > -} > - > -static int reader_probe(struct pcmcia_device *link) > -{ > - struct reader_dev *dev; > - int i, ret; > - > - for (i = 0; i < CM_MAX_DEV; i++) { > - if (dev_table[i] == NULL) > - break; > - } > - > - if (i == CM_MAX_DEV) > - return -ENODEV; > - > - dev = kzalloc(sizeof(struct reader_dev), GFP_KERNEL); > - if (dev == NULL) > - return -ENOMEM; > - > - dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT; > - dev->buffer_status = 0; > - > - link->priv = dev; > - dev->p_dev = link; > - > - dev_table[i] = link; > - > - init_waitqueue_head(&dev->devq); > - init_waitqueue_head(&dev->poll_wait); > - init_waitqueue_head(&dev->read_wait); > - init_waitqueue_head(&dev->write_wait); > - timer_setup(&dev->poll_timer, cm4040_do_poll, 0); > - > - ret = reader_config(link, i); > - if (ret) { > - dev_table[i] = NULL; > - kfree(dev); > - return ret; > - } > - > - device_create(cmx_class, NULL, MKDEV(major, i), NULL, "cmx%d", i); > - > - return 0; > -} > - > -static void reader_detach(struct pcmcia_device *link) > -{ > - struct reader_dev *dev = link->priv; > - int devno; > - > - /* find device */ > - for (devno = 0; devno < CM_MAX_DEV; devno++) { > - if (dev_table[devno] == link) > - break; > - } > - if (devno == CM_MAX_DEV) > - return; > - > - reader_release(link); > - > - dev_table[devno] = NULL; > - kfree(dev); > - > - device_destroy(cmx_class, MKDEV(major, devno)); > - > - return; > -} > - > -static const struct file_operations reader_fops = { > - .owner = THIS_MODULE, > - .read = cm4040_read, > - .write = cm4040_write, > - .open = cm4040_open, > - .release = cm4040_close, > - .poll = cm4040_poll, > - .llseek = no_llseek, > -}; > - > -static const struct pcmcia_device_id cm4040_ids[] = { > - PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0200), > - PCMCIA_DEVICE_PROD_ID12("OMNIKEY", "CardMan 4040", > - 0xE32CDD8C, 0x8F23318B), > - PCMCIA_DEVICE_NULL, > -}; > -MODULE_DEVICE_TABLE(pcmcia, cm4040_ids); > - > -static struct pcmcia_driver reader_driver = { > - .owner = THIS_MODULE, > - .name = "cm4040_cs", > - .probe = reader_probe, > - .remove = reader_detach, > - .id_table = cm4040_ids, > -}; > - > -static int __init cm4040_init(void) > -{ > - int rc; > - > - cmx_class = class_create(THIS_MODULE, "cardman_4040"); > - if (IS_ERR(cmx_class)) > - return PTR_ERR(cmx_class); > - > - major = register_chrdev(0, DEVICE_NAME, &reader_fops); > - if (major < 0) { > - printk(KERN_WARNING MODULE_NAME > - ": could not get major number\n"); > - class_destroy(cmx_class); > - return major; > - } > - > - rc = pcmcia_register_driver(&reader_driver); > - if (rc < 0) { > - unregister_chrdev(major, DEVICE_NAME); > - class_destroy(cmx_class); > - return rc; > - } > - > - return 0; > -} > - > -static void __exit cm4040_exit(void) > -{ > - pcmcia_unregister_driver(&reader_driver); > - unregister_chrdev(major, DEVICE_NAME); > - class_destroy(cmx_class); > -} > - > -module_init(cm4040_init); > -module_exit(cm4040_exit); > -MODULE_LICENSE("Dual BSD/GPL"); > diff --git a/drivers/char/pcmcia/cm4040_cs.h b/drivers/char/pcmcia/cm4040_cs.h > deleted file mode 100644 > index e2ffff995d51..000000000000 > --- a/drivers/char/pcmcia/cm4040_cs.h > +++ /dev/null > @@ -1,48 +0,0 @@ > -/* SPDX-License-Identifier: GPL-2.0 */ > -#ifndef _CM4040_H_ > -#define _CM4040_H_ > - > -#define CM_MAX_DEV 4 > - > -#define DEVICE_NAME "cmx" > -#define MODULE_NAME "cm4040_cs" > - > -#define REG_OFFSET_BULK_OUT 0 > -#define REG_OFFSET_BULK_IN 0 > -#define REG_OFFSET_BUFFER_STATUS 1 > -#define REG_OFFSET_SYNC_CONTROL 2 > - > -#define BSR_BULK_IN_FULL 0x02 > -#define BSR_BULK_OUT_FULL 0x01 > - > -#define SCR_HOST_TO_READER_START 0x80 > -#define SCR_ABORT 0x40 > -#define SCR_EN_NOTIFY 0x20 > -#define SCR_ACK_NOTIFY 0x10 > -#define SCR_READER_TO_HOST_DONE 0x08 > -#define SCR_HOST_TO_READER_DONE 0x04 > -#define SCR_PULSE_INTERRUPT 0x02 > -#define SCR_POWER_DOWN 0x01 > - > - > -#define CMD_PC_TO_RDR_ICCPOWERON 0x62 > -#define CMD_PC_TO_RDR_GETSLOTSTATUS 0x65 > -#define CMD_PC_TO_RDR_ICCPOWEROFF 0x63 > -#define CMD_PC_TO_RDR_SECURE 0x69 > -#define CMD_PC_TO_RDR_GETPARAMETERS 0x6C > -#define CMD_PC_TO_RDR_RESETPARAMETERS 0x6D > -#define CMD_PC_TO_RDR_SETPARAMETERS 0x61 > -#define CMD_PC_TO_RDR_XFRBLOCK 0x6F > -#define CMD_PC_TO_RDR_ESCAPE 0x6B > -#define CMD_PC_TO_RDR_ICCCLOCK 0x6E > -#define CMD_PC_TO_RDR_TEST_SECURE 0x74 > -#define CMD_PC_TO_RDR_OK_SECURE 0x89 > - > - > -#define CMD_RDR_TO_PC_SLOTSTATUS 0x81 > -#define CMD_RDR_TO_PC_DATABLOCK 0x80 > -#define CMD_RDR_TO_PC_PARAMETERS 0x82 > -#define CMD_RDR_TO_PC_ESCAPE 0x83 > -#define CMD_RDR_TO_PC_OK_SECURE 0x89 > - > -#endif /* _CM4040_H_ */ > diff --git a/drivers/char/pcmcia/scr24x_cs.c b/drivers/char/pcmcia/scr24x_cs.c > deleted file mode 100644 > index 1bdce08fae3d..000000000000 > --- a/drivers/char/pcmcia/scr24x_cs.c > +++ /dev/null > @@ -1,359 +0,0 @@ > -// SPDX-License-Identifier: GPL-2.0-or-later > -/* > - * SCR24x PCMCIA Smart Card Reader Driver > - * > - * Copyright (C) 2005-2006 TL Sudheendran > - * Copyright (C) 2016 Lubomir Rintel > - * > - * Derived from "scr24x_v4.2.6_Release.tar.gz" driver by TL Sudheendran. > - */ > - > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > - > -#include > -#include > - > -#define CCID_HEADER_SIZE 10 > -#define CCID_LENGTH_OFFSET 1 > -#define CCID_MAX_LEN 271 > - > -#define SCR24X_DATA(n) (1 + n) > -#define SCR24X_CMD_STATUS 7 > -#define CMD_START 0x40 > -#define CMD_WRITE_BYTE 0x41 > -#define CMD_READ_BYTE 0x42 > -#define STATUS_BUSY 0x80 > - > -struct scr24x_dev { > - struct device *dev; > - struct cdev c_dev; > - unsigned char buf[CCID_MAX_LEN]; > - int devno; > - struct mutex lock; > - struct kref refcnt; > - u8 __iomem *regs; > -}; > - > -#define SCR24X_DEVS 8 > -static DECLARE_BITMAP(scr24x_minors, SCR24X_DEVS); > - > -static struct class *scr24x_class; > -static dev_t scr24x_devt; > - > -static void scr24x_delete(struct kref *kref) > -{ > - struct scr24x_dev *dev = container_of(kref, struct scr24x_dev, > - refcnt); > - > - kfree(dev); > -} > - > -static int scr24x_wait_ready(struct scr24x_dev *dev) > -{ > - u_char status; > - int timeout = 100; > - > - do { > - status = ioread8(dev->regs + SCR24X_CMD_STATUS); > - if (!(status & STATUS_BUSY)) > - return 0; > - > - msleep(20); > - } while (--timeout); > - > - return -EIO; > -} > - > -static int scr24x_open(struct inode *inode, struct file *filp) > -{ > - struct scr24x_dev *dev = container_of(inode->i_cdev, > - struct scr24x_dev, c_dev); > - > - kref_get(&dev->refcnt); > - filp->private_data = dev; > - > - return stream_open(inode, filp); > -} > - > -static int scr24x_release(struct inode *inode, struct file *filp) > -{ > - struct scr24x_dev *dev = filp->private_data; > - > - /* We must not take the dev->lock here as scr24x_delete() > - * might be called to remove the dev structure altogether. > - * We don't need the lock anyway, since after the reference > - * acquired in probe() is released in remove() the chrdev > - * is already unregistered and noone can possibly acquire > - * a reference via open() anymore. */ > - kref_put(&dev->refcnt, scr24x_delete); > - return 0; > -} > - > -static int read_chunk(struct scr24x_dev *dev, size_t offset, size_t limit) > -{ > - size_t i, y; > - int ret; > - > - for (i = offset; i < limit; i += 5) { > - iowrite8(CMD_READ_BYTE, dev->regs + SCR24X_CMD_STATUS); > - ret = scr24x_wait_ready(dev); > - if (ret < 0) > - return ret; > - > - for (y = 0; y < 5 && i + y < limit; y++) > - dev->buf[i + y] = ioread8(dev->regs + SCR24X_DATA(y)); > - } > - > - return 0; > -} > - > -static ssize_t scr24x_read(struct file *filp, char __user *buf, size_t count, > - loff_t *ppos) > -{ > - struct scr24x_dev *dev = filp->private_data; > - int ret; > - int len; > - > - if (count < CCID_HEADER_SIZE) > - return -EINVAL; > - > - if (mutex_lock_interruptible(&dev->lock)) > - return -ERESTARTSYS; > - > - if (!dev->dev) { > - ret = -ENODEV; > - goto out; > - } > - > - ret = scr24x_wait_ready(dev); > - if (ret < 0) > - goto out; > - len = CCID_HEADER_SIZE; > - ret = read_chunk(dev, 0, len); > - if (ret < 0) > - goto out; > - > - len += le32_to_cpu(*(__le32 *)(&dev->buf[CCID_LENGTH_OFFSET])); > - if (len > sizeof(dev->buf)) { > - ret = -EIO; > - goto out; > - } > - ret = read_chunk(dev, CCID_HEADER_SIZE, len); > - if (ret < 0) > - goto out; > - > - if (len < count) > - count = len; > - > - if (copy_to_user(buf, dev->buf, count)) { > - ret = -EFAULT; > - goto out; > - } > - > - ret = count; > -out: > - mutex_unlock(&dev->lock); > - return ret; > -} > - > -static ssize_t scr24x_write(struct file *filp, const char __user *buf, > - size_t count, loff_t *ppos) > -{ > - struct scr24x_dev *dev = filp->private_data; > - size_t i, y; > - int ret; > - > - if (mutex_lock_interruptible(&dev->lock)) > - return -ERESTARTSYS; > - > - if (!dev->dev) { > - ret = -ENODEV; > - goto out; > - } > - > - if (count > sizeof(dev->buf)) { > - ret = -EINVAL; > - goto out; > - } > - > - if (copy_from_user(dev->buf, buf, count)) { > - ret = -EFAULT; > - goto out; > - } > - > - ret = scr24x_wait_ready(dev); > - if (ret < 0) > - goto out; > - > - iowrite8(CMD_START, dev->regs + SCR24X_CMD_STATUS); > - ret = scr24x_wait_ready(dev); > - if (ret < 0) > - goto out; > - > - for (i = 0; i < count; i += 5) { > - for (y = 0; y < 5 && i + y < count; y++) > - iowrite8(dev->buf[i + y], dev->regs + SCR24X_DATA(y)); > - > - iowrite8(CMD_WRITE_BYTE, dev->regs + SCR24X_CMD_STATUS); > - ret = scr24x_wait_ready(dev); > - if (ret < 0) > - goto out; > - } > - > - ret = count; > -out: > - mutex_unlock(&dev->lock); > - return ret; > -} > - > -static const struct file_operations scr24x_fops = { > - .owner = THIS_MODULE, > - .read = scr24x_read, > - .write = scr24x_write, > - .open = scr24x_open, > - .release = scr24x_release, > - .llseek = no_llseek, > -}; > - > -static int scr24x_config_check(struct pcmcia_device *link, void *priv_data) > -{ > - if (resource_size(link->resource[PCMCIA_IOPORT_0]) != 0x11) > - return -ENODEV; > - return pcmcia_request_io(link); > -} > - > -static int scr24x_probe(struct pcmcia_device *link) > -{ > - struct scr24x_dev *dev; > - int ret; > - > - dev = kzalloc(sizeof(*dev), GFP_KERNEL); > - if (!dev) > - return -ENOMEM; > - > - dev->devno = find_first_zero_bit(scr24x_minors, SCR24X_DEVS); > - if (dev->devno >= SCR24X_DEVS) { > - ret = -EBUSY; > - goto err; > - } > - > - mutex_init(&dev->lock); > - kref_init(&dev->refcnt); > - > - link->priv = dev; > - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; > - > - ret = pcmcia_loop_config(link, scr24x_config_check, NULL); > - if (ret < 0) > - goto err; > - > - dev->dev = &link->dev; > - dev->regs = devm_ioport_map(&link->dev, > - link->resource[PCMCIA_IOPORT_0]->start, > - resource_size(link->resource[PCMCIA_IOPORT_0])); > - if (!dev->regs) { > - ret = -EIO; > - goto err; > - } > - > - cdev_init(&dev->c_dev, &scr24x_fops); > - dev->c_dev.owner = THIS_MODULE; > - ret = cdev_add(&dev->c_dev, MKDEV(MAJOR(scr24x_devt), dev->devno), 1); > - if (ret < 0) > - goto err; > - > - ret = pcmcia_enable_device(link); > - if (ret < 0) { > - pcmcia_disable_device(link); > - goto err; > - } > - > - device_create(scr24x_class, NULL, MKDEV(MAJOR(scr24x_devt), dev->devno), > - NULL, "scr24x%d", dev->devno); > - > - dev_info(&link->dev, "SCR24x Chip Card Interface\n"); > - return 0; > - > -err: > - if (dev->devno < SCR24X_DEVS) > - clear_bit(dev->devno, scr24x_minors); > - kfree (dev); > - return ret; > -} > - > -static void scr24x_remove(struct pcmcia_device *link) > -{ > - struct scr24x_dev *dev = (struct scr24x_dev *)link->priv; > - > - device_destroy(scr24x_class, MKDEV(MAJOR(scr24x_devt), dev->devno)); > - mutex_lock(&dev->lock); > - pcmcia_disable_device(link); > - cdev_del(&dev->c_dev); > - clear_bit(dev->devno, scr24x_minors); > - dev->dev = NULL; > - mutex_unlock(&dev->lock); > - > - kref_put(&dev->refcnt, scr24x_delete); > -} > - > -static const struct pcmcia_device_id scr24x_ids[] = { > - PCMCIA_DEVICE_PROD_ID12("HP", "PC Card Smart Card Reader", > - 0x53cb94f9, 0xbfdf89a5), > - PCMCIA_DEVICE_PROD_ID1("SCR241 PCMCIA", 0x6271efa3), > - PCMCIA_DEVICE_PROD_ID1("SCR243 PCMCIA", 0x2054e8de), > - PCMCIA_DEVICE_PROD_ID1("SCR24x PCMCIA", 0x54a33665), > - PCMCIA_DEVICE_NULL > -}; > -MODULE_DEVICE_TABLE(pcmcia, scr24x_ids); > - > -static struct pcmcia_driver scr24x_driver = { > - .owner = THIS_MODULE, > - .name = "scr24x_cs", > - .probe = scr24x_probe, > - .remove = scr24x_remove, > - .id_table = scr24x_ids, > -}; > - > -static int __init scr24x_init(void) > -{ > - int ret; > - > - scr24x_class = class_create(THIS_MODULE, "scr24x"); > - if (IS_ERR(scr24x_class)) > - return PTR_ERR(scr24x_class); > - > - ret = alloc_chrdev_region(&scr24x_devt, 0, SCR24X_DEVS, "scr24x"); > - if (ret < 0) { > - class_destroy(scr24x_class); > - return ret; > - } > - > - ret = pcmcia_register_driver(&scr24x_driver); > - if (ret < 0) { > - unregister_chrdev_region(scr24x_devt, SCR24X_DEVS); > - class_destroy(scr24x_class); > - } > - > - return ret; > -} > - > -static void __exit scr24x_exit(void) > -{ > - pcmcia_unregister_driver(&scr24x_driver); > - unregister_chrdev_region(scr24x_devt, SCR24X_DEVS); > - class_destroy(scr24x_class); > -} > - > -module_init(scr24x_init); > -module_exit(scr24x_exit); > - > -MODULE_AUTHOR("Lubomir Rintel"); > -MODULE_DESCRIPTION("SCR24x PCMCIA Smart Card Reader Driver"); > -MODULE_LICENSE("GPL"); > diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c > deleted file mode 100644 > index 1154a67044a9..000000000000 > --- a/drivers/char/pcmcia/synclink_cs.c > +++ /dev/null > @@ -1,4280 +0,0 @@ > -/* > - * linux/drivers/char/pcmcia/synclink_cs.c > - * > - * $Id: synclink_cs.c,v 4.34 2005/09/08 13:20:54 paulkf Exp $ > - * > - * Device driver for Microgate SyncLink PC Card > - * multiprotocol serial adapter. > - * > - * written by Paul Fulghum for Microgate Corporation > - * paulkf@microgate.com > - * > - * Microgate and SyncLink are trademarks of Microgate Corporation > - * > - * This code is released under the GNU General Public License (GPL) > - * > - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED > - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES > - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE > - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, > - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES > - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR > - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, > - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED > - * OF THE POSSIBILITY OF SUCH DAMAGE. > - */ > - > -#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) > -#if defined(__i386__) > -# define BREAKPOINT() asm(" int $3"); > -#else > -# define BREAKPOINT() { } > -#endif > - > -#define MAX_DEVICE_COUNT 4 > - > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > - > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > - > -#include > -#include > -#include > - > -#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_CS_MODULE)) > -#define SYNCLINK_GENERIC_HDLC 1 > -#else > -#define SYNCLINK_GENERIC_HDLC 0 > -#endif > - > -#define GET_USER(error,value,addr) error = get_user(value,addr) > -#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 > -#define PUT_USER(error,value,addr) error = put_user(value,addr) > -#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 > - > -#include > - > -static MGSL_PARAMS default_params = { > - MGSL_MODE_HDLC, /* unsigned long mode */ > - 0, /* unsigned char loopback; */ > - HDLC_FLAG_UNDERRUN_ABORT15, /* unsigned short flags; */ > - HDLC_ENCODING_NRZI_SPACE, /* unsigned char encoding; */ > - 0, /* unsigned long clock_speed; */ > - 0xff, /* unsigned char addr_filter; */ > - HDLC_CRC_16_CCITT, /* unsigned short crc_type; */ > - HDLC_PREAMBLE_LENGTH_8BITS, /* unsigned char preamble_length; */ > - HDLC_PREAMBLE_PATTERN_NONE, /* unsigned char preamble; */ > - 9600, /* unsigned long data_rate; */ > - 8, /* unsigned char data_bits; */ > - 1, /* unsigned char stop_bits; */ > - ASYNC_PARITY_NONE /* unsigned char parity; */ > -}; > - > -typedef struct { > - int count; > - unsigned char status; > - char data[1]; > -} RXBUF; > - > -/* The queue of BH actions to be performed */ > - > -#define BH_RECEIVE 1 > -#define BH_TRANSMIT 2 > -#define BH_STATUS 4 > - > -#define IO_PIN_SHUTDOWN_LIMIT 100 > - > -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) > - > -struct _input_signal_events { > - int ri_up; > - int ri_down; > - int dsr_up; > - int dsr_down; > - int dcd_up; > - int dcd_down; > - int cts_up; > - int cts_down; > -}; > - > - > -/* > - * Device instance data structure > - */ > - > -typedef struct _mgslpc_info { > - struct tty_port port; > - void *if_ptr; /* General purpose pointer (used by SPPP) */ > - int magic; > - int line; > - > - struct mgsl_icount icount; > - > - int timeout; > - int x_char; /* xon/xoff character */ > - unsigned char read_status_mask; > - unsigned char ignore_status_mask; > - > - unsigned char *tx_buf; > - int tx_put; > - int tx_get; > - int tx_count; > - > - /* circular list of fixed length rx buffers */ > - > - unsigned char *rx_buf; /* memory allocated for all rx buffers */ > - int rx_buf_total_size; /* size of memory allocated for rx buffers */ > - int rx_put; /* index of next empty rx buffer */ > - int rx_get; /* index of next full rx buffer */ > - int rx_buf_size; /* size in bytes of single rx buffer */ > - int rx_buf_count; /* total number of rx buffers */ > - int rx_frame_count; /* number of full rx buffers */ > - > - wait_queue_head_t status_event_wait_q; > - wait_queue_head_t event_wait_q; > - struct timer_list tx_timer; /* HDLC transmit timeout timer */ > - struct _mgslpc_info *next_device; /* device list link */ > - > - unsigned short imra_value; > - unsigned short imrb_value; > - unsigned char pim_value; > - > - spinlock_t lock; > - struct work_struct task; /* task structure for scheduling bh */ > - > - u32 max_frame_size; > - > - u32 pending_bh; > - > - bool bh_running; > - bool bh_requested; > - > - int dcd_chkcount; /* check counts to prevent */ > - int cts_chkcount; /* too many IRQs if a signal */ > - int dsr_chkcount; /* is floating */ > - int ri_chkcount; > - > - bool rx_enabled; > - bool rx_overflow; > - > - bool tx_enabled; > - bool tx_active; > - bool tx_aborting; > - u32 idle_mode; > - > - int if_mode; /* serial interface selection (RS-232, v.35 etc) */ > - > - char device_name[25]; /* device instance name */ > - > - unsigned int io_base; /* base I/O address of adapter */ > - unsigned int irq_level; > - > - MGSL_PARAMS params; /* communications parameters */ > - > - unsigned char serial_signals; /* current serial signal states */ > - > - bool irq_occurred; /* for diagnostics use */ > - char testing_irq; > - unsigned int init_error; /* startup error (DIAGS) */ > - > - bool drop_rts_on_tx_done; > - > - struct _input_signal_events input_signal_events; > - > - /* PCMCIA support */ > - struct pcmcia_device *p_dev; > - int stop; > - > - /* SPPP/Cisco HDLC device parts */ > - int netcount; > - spinlock_t netlock; > - > -#if SYNCLINK_GENERIC_HDLC > - struct net_device *netdev; > -#endif > - > -} MGSLPC_INFO; > - > -#define MGSLPC_MAGIC 0x5402 > - > -/* > - * The size of the serial xmit buffer is 1 page, or 4096 bytes > - */ > -#define TXBUFSIZE 4096 > - > - > -#define CHA 0x00 /* channel A offset */ > -#define CHB 0x40 /* channel B offset */ > - > -/* > - * FIXME: PPC has PVR defined in asm/reg.h. For now we just undef it. > - */ > -#undef PVR > - > -#define RXFIFO 0 > -#define TXFIFO 0 > -#define STAR 0x20 > -#define CMDR 0x20 > -#define RSTA 0x21 > -#define PRE 0x21 > -#define MODE 0x22 > -#define TIMR 0x23 > -#define XAD1 0x24 > -#define XAD2 0x25 > -#define RAH1 0x26 > -#define RAH2 0x27 > -#define DAFO 0x27 > -#define RAL1 0x28 > -#define RFC 0x28 > -#define RHCR 0x29 > -#define RAL2 0x29 > -#define RBCL 0x2a > -#define XBCL 0x2a > -#define RBCH 0x2b > -#define XBCH 0x2b > -#define CCR0 0x2c > -#define CCR1 0x2d > -#define CCR2 0x2e > -#define CCR3 0x2f > -#define VSTR 0x34 > -#define BGR 0x34 > -#define RLCR 0x35 > -#define AML 0x36 > -#define AMH 0x37 > -#define GIS 0x38 > -#define IVA 0x38 > -#define IPC 0x39 > -#define ISR 0x3a > -#define IMR 0x3a > -#define PVR 0x3c > -#define PIS 0x3d > -#define PIM 0x3d > -#define PCR 0x3e > -#define CCR4 0x3f > - > -// IMR/ISR > - > -#define IRQ_BREAK_ON BIT15 // rx break detected > -#define IRQ_DATAOVERRUN BIT14 // receive data overflow > -#define IRQ_ALLSENT BIT13 // all sent > -#define IRQ_UNDERRUN BIT12 // transmit data underrun > -#define IRQ_TIMER BIT11 // timer interrupt > -#define IRQ_CTS BIT10 // CTS status change > -#define IRQ_TXREPEAT BIT9 // tx message repeat > -#define IRQ_TXFIFO BIT8 // transmit pool ready > -#define IRQ_RXEOM BIT7 // receive message end > -#define IRQ_EXITHUNT BIT6 // receive frame start > -#define IRQ_RXTIME BIT6 // rx char timeout > -#define IRQ_DCD BIT2 // carrier detect status change > -#define IRQ_OVERRUN BIT1 // receive frame overflow > -#define IRQ_RXFIFO BIT0 // receive pool full > - > -// STAR > - > -#define XFW BIT6 // transmit FIFO write enable > -#define CEC BIT2 // command executing > -#define CTS BIT1 // CTS state > - > -#define PVR_DTR BIT0 > -#define PVR_DSR BIT1 > -#define PVR_RI BIT2 > -#define PVR_AUTOCTS BIT3 > -#define PVR_RS232 0x20 /* 0010b */ > -#define PVR_V35 0xe0 /* 1110b */ > -#define PVR_RS422 0x40 /* 0100b */ > - > -/* Register access functions */ > - > -#define write_reg(info, reg, val) outb((val),(info)->io_base + (reg)) > -#define read_reg(info, reg) inb((info)->io_base + (reg)) > - > -#define read_reg16(info, reg) inw((info)->io_base + (reg)) > -#define write_reg16(info, reg, val) outw((val), (info)->io_base + (reg)) > - > -#define set_reg_bits(info, reg, mask) \ > - write_reg(info, (reg), \ > - (unsigned char) (read_reg(info, (reg)) | (mask))) > -#define clear_reg_bits(info, reg, mask) \ > - write_reg(info, (reg), \ > - (unsigned char) (read_reg(info, (reg)) & ~(mask))) > -/* > - * interrupt enable/disable routines > - */ > -static void irq_disable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask) > -{ > - if (channel == CHA) { > - info->imra_value |= mask; > - write_reg16(info, CHA + IMR, info->imra_value); > - } else { > - info->imrb_value |= mask; > - write_reg16(info, CHB + IMR, info->imrb_value); > - } > -} > -static void irq_enable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask) > -{ > - if (channel == CHA) { > - info->imra_value &= ~mask; > - write_reg16(info, CHA + IMR, info->imra_value); > - } else { > - info->imrb_value &= ~mask; > - write_reg16(info, CHB + IMR, info->imrb_value); > - } > -} > - > -#define port_irq_disable(info, mask) \ > - { info->pim_value |= (mask); write_reg(info, PIM, info->pim_value); } > - > -#define port_irq_enable(info, mask) \ > - { info->pim_value &= ~(mask); write_reg(info, PIM, info->pim_value); } > - > -static void rx_start(MGSLPC_INFO *info); > -static void rx_stop(MGSLPC_INFO *info); > - > -static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty); > -static void tx_stop(MGSLPC_INFO *info); > -static void tx_set_idle(MGSLPC_INFO *info); > - > -static void get_signals(MGSLPC_INFO *info); > -static void set_signals(MGSLPC_INFO *info); > - > -static void reset_device(MGSLPC_INFO *info); > - > -static void hdlc_mode(MGSLPC_INFO *info); > -static void async_mode(MGSLPC_INFO *info); > - > -static void tx_timeout(struct timer_list *t); > - > -static bool carrier_raised(struct tty_port *port); > -static void dtr_rts(struct tty_port *port, bool active); > - > -#if SYNCLINK_GENERIC_HDLC > -#define dev_to_port(D) (dev_to_hdlc(D)->priv) > -static void hdlcdev_tx_done(MGSLPC_INFO *info); > -static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size); > -static int hdlcdev_init(MGSLPC_INFO *info); > -static void hdlcdev_exit(MGSLPC_INFO *info); > -#endif > - > -static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit); > - > -static bool register_test(MGSLPC_INFO *info); > -static bool irq_test(MGSLPC_INFO *info); > -static int adapter_test(MGSLPC_INFO *info); > - > -static int claim_resources(MGSLPC_INFO *info); > -static void release_resources(MGSLPC_INFO *info); > -static int mgslpc_add_device(MGSLPC_INFO *info); > -static void mgslpc_remove_device(MGSLPC_INFO *info); > - > -static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty); > -static void rx_reset_buffers(MGSLPC_INFO *info); > -static int rx_alloc_buffers(MGSLPC_INFO *info); > -static void rx_free_buffers(MGSLPC_INFO *info); > - > -static irqreturn_t mgslpc_isr(int irq, void *dev_id); > - > -/* > - * Bottom half interrupt handlers > - */ > -static void bh_handler(struct work_struct *work); > -static void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty); > -static void bh_status(MGSLPC_INFO *info); > - > -/* > - * ioctl handlers > - */ > -static int tiocmget(struct tty_struct *tty); > -static int tiocmset(struct tty_struct *tty, > - unsigned int set, unsigned int clear); > -static int get_stats(MGSLPC_INFO *info, struct mgsl_icount __user *user_icount); > -static int get_params(MGSLPC_INFO *info, MGSL_PARAMS __user *user_params); > -static int set_params(MGSLPC_INFO *info, MGSL_PARAMS __user *new_params, struct tty_struct *tty); > -static int get_txidle(MGSLPC_INFO *info, int __user *idle_mode); > -static int set_txidle(MGSLPC_INFO *info, int idle_mode); > -static int set_txenable(MGSLPC_INFO *info, int enable, struct tty_struct *tty); > -static int tx_abort(MGSLPC_INFO *info); > -static int set_rxenable(MGSLPC_INFO *info, int enable); > -static int wait_events(MGSLPC_INFO *info, int __user *mask); > - > -static MGSLPC_INFO *mgslpc_device_list = NULL; > -static int mgslpc_device_count = 0; > - > -/* > - * Set this param to non-zero to load eax with the > - * .text section address and breakpoint on module load. > - * This is useful for use with gdb and add-symbol-file command. > - */ > -static bool break_on_load; > - > -/* > - * Driver major number, defaults to zero to get auto > - * assigned major number. May be forced as module parameter. > - */ > -static int ttymajor=0; > - > -static int debug_level = 0; > -static int maxframe[MAX_DEVICE_COUNT] = {0,}; > - > -module_param(break_on_load, bool, 0); > -module_param(ttymajor, int, 0); > -module_param(debug_level, int, 0); > -module_param_array(maxframe, int, NULL, 0); > - > -MODULE_LICENSE("GPL"); > - > -static char *driver_name = "SyncLink PC Card driver"; > -static char *driver_version = "$Revision: 4.34 $"; > - > -static struct tty_driver *serial_driver; > - > -/* number of characters left in xmit buffer before we ask for more */ > -#define WAKEUP_CHARS 256 > - > -static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty); > -static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout); > - > -/* PCMCIA prototypes */ > - > -static int mgslpc_config(struct pcmcia_device *link); > -static void mgslpc_release(u_long arg); > -static void mgslpc_detach(struct pcmcia_device *p_dev); > - > -/* > - * 1st function defined in .text section. Calling this function in > - * init_module() followed by a breakpoint allows a remote debugger > - * (gdb) to get the .text address for the add-symbol-file command. > - * This allows remote debugging of dynamically loadable modules. > - */ > -static void* mgslpc_get_text_ptr(void) > -{ > - return mgslpc_get_text_ptr; > -} > - > -/* > - * line discipline callback wrappers > - * > - * The wrappers maintain line discipline references > - * while calling into the line discipline. > - * > - * ldisc_receive_buf - pass receive data to line discipline > - */ > - > -static void ldisc_receive_buf(struct tty_struct *tty, > - const __u8 *data, char *flags, int count) > -{ > - struct tty_ldisc *ld; > - if (!tty) > - return; > - ld = tty_ldisc_ref(tty); > - if (ld) { > - if (ld->ops->receive_buf) > - ld->ops->receive_buf(tty, data, flags, count); > - tty_ldisc_deref(ld); > - } > -} > - > -static const struct tty_port_operations mgslpc_port_ops = { > - .carrier_raised = carrier_raised, > - .dtr_rts = dtr_rts > -}; > - > -static int mgslpc_probe(struct pcmcia_device *link) > -{ > - MGSLPC_INFO *info; > - int ret; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("mgslpc_attach\n"); > - > - info = kzalloc(sizeof(MGSLPC_INFO), GFP_KERNEL); > - if (!info) { > - printk("Error can't allocate device instance data\n"); > - return -ENOMEM; > - } > - > - info->magic = MGSLPC_MAGIC; > - tty_port_init(&info->port); > - info->port.ops = &mgslpc_port_ops; > - INIT_WORK(&info->task, bh_handler); > - info->max_frame_size = 4096; > - init_waitqueue_head(&info->status_event_wait_q); > - init_waitqueue_head(&info->event_wait_q); > - spin_lock_init(&info->lock); > - spin_lock_init(&info->netlock); > - memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); > - info->idle_mode = HDLC_TXIDLE_FLAGS; > - info->imra_value = 0xffff; > - info->imrb_value = 0xffff; > - info->pim_value = 0xff; > - > - info->p_dev = link; > - link->priv = info; > - > - /* Initialize the struct pcmcia_device structure */ > - > - ret = mgslpc_config(link); > - if (ret != 0) > - goto failed; > - > - ret = mgslpc_add_device(info); > - if (ret != 0) > - goto failed_release; > - > - return 0; > - > -failed_release: > - mgslpc_release((u_long)link); > -failed: > - tty_port_destroy(&info->port); > - kfree(info); > - return ret; > -} > - > -/* Card has been inserted. > - */ > - > -static int mgslpc_ioprobe(struct pcmcia_device *p_dev, void *priv_data) > -{ > - return pcmcia_request_io(p_dev); > -} > - > -static int mgslpc_config(struct pcmcia_device *link) > -{ > - MGSLPC_INFO *info = link->priv; > - int ret; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("mgslpc_config(0x%p)\n", link); > - > - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; > - > - ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL); > - if (ret != 0) > - goto failed; > - > - link->config_index = 8; > - link->config_regs = PRESENT_OPTION; > - > - ret = pcmcia_request_irq(link, mgslpc_isr); > - if (ret) > - goto failed; > - ret = pcmcia_enable_device(link); > - if (ret) > - goto failed; > - > - info->io_base = link->resource[0]->start; > - info->irq_level = link->irq; > - return 0; > - > -failed: > - mgslpc_release((u_long)link); > - return -ENODEV; > -} > - > -/* Card has been removed. > - * Unregister device and release PCMCIA configuration. > - * If device is open, postpone until it is closed. > - */ > -static void mgslpc_release(u_long arg) > -{ > - struct pcmcia_device *link = (struct pcmcia_device *)arg; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("mgslpc_release(0x%p)\n", link); > - > - pcmcia_disable_device(link); > -} > - > -static void mgslpc_detach(struct pcmcia_device *link) > -{ > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("mgslpc_detach(0x%p)\n", link); > - > - ((MGSLPC_INFO *)link->priv)->stop = 1; > - mgslpc_release((u_long)link); > - > - mgslpc_remove_device((MGSLPC_INFO *)link->priv); > -} > - > -static int mgslpc_suspend(struct pcmcia_device *link) > -{ > - MGSLPC_INFO *info = link->priv; > - > - info->stop = 1; > - > - return 0; > -} > - > -static int mgslpc_resume(struct pcmcia_device *link) > -{ > - MGSLPC_INFO *info = link->priv; > - > - info->stop = 0; > - > - return 0; > -} > - > - > -static inline bool mgslpc_paranoia_check(MGSLPC_INFO *info, > - char *name, const char *routine) > -{ > -#ifdef MGSLPC_PARANOIA_CHECK > - static const char *badmagic = > - "Warning: bad magic number for mgsl struct (%s) in %s\n"; > - static const char *badinfo = > - "Warning: null mgslpc_info for (%s) in %s\n"; > - > - if (!info) { > - printk(badinfo, name, routine); > - return true; > - } > - if (info->magic != MGSLPC_MAGIC) { > - printk(badmagic, name, routine); > - return true; > - } > -#else > - if (!info) > - return true; > -#endif > - return false; > -} > - > - > -#define CMD_RXFIFO BIT7 // release current rx FIFO > -#define CMD_RXRESET BIT6 // receiver reset > -#define CMD_RXFIFO_READ BIT5 > -#define CMD_START_TIMER BIT4 > -#define CMD_TXFIFO BIT3 // release current tx FIFO > -#define CMD_TXEOM BIT1 // transmit end message > -#define CMD_TXRESET BIT0 // transmit reset > - > -static bool wait_command_complete(MGSLPC_INFO *info, unsigned char channel) > -{ > - int i = 0; > - /* wait for command completion */ > - while (read_reg(info, (unsigned char)(channel+STAR)) & BIT2) { > - udelay(1); > - if (i++ == 1000) > - return false; > - } > - return true; > -} > - > -static void issue_command(MGSLPC_INFO *info, unsigned char channel, unsigned char cmd) > -{ > - wait_command_complete(info, channel); > - write_reg(info, (unsigned char) (channel + CMDR), cmd); > -} > - > -static void tx_pause(struct tty_struct *tty) > -{ > - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; > - unsigned long flags; > - > - if (mgslpc_paranoia_check(info, tty->name, "tx_pause")) > - return; > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("tx_pause(%s)\n", info->device_name); > - > - spin_lock_irqsave(&info->lock, flags); > - if (info->tx_enabled) > - tx_stop(info); > - spin_unlock_irqrestore(&info->lock, flags); > -} > - > -static void tx_release(struct tty_struct *tty) > -{ > - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; > - unsigned long flags; > - > - if (mgslpc_paranoia_check(info, tty->name, "tx_release")) > - return; > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("tx_release(%s)\n", info->device_name); > - > - spin_lock_irqsave(&info->lock, flags); > - if (!info->tx_enabled) > - tx_start(info, tty); > - spin_unlock_irqrestore(&info->lock, flags); > -} > - > -/* Return next bottom half action to perform. > - * or 0 if nothing to do. > - */ > -static int bh_action(MGSLPC_INFO *info) > -{ > - unsigned long flags; > - int rc = 0; > - > - spin_lock_irqsave(&info->lock, flags); > - > - if (info->pending_bh & BH_RECEIVE) { > - info->pending_bh &= ~BH_RECEIVE; > - rc = BH_RECEIVE; > - } else if (info->pending_bh & BH_TRANSMIT) { > - info->pending_bh &= ~BH_TRANSMIT; > - rc = BH_TRANSMIT; > - } else if (info->pending_bh & BH_STATUS) { > - info->pending_bh &= ~BH_STATUS; > - rc = BH_STATUS; > - } > - > - if (!rc) { > - /* Mark BH routine as complete */ > - info->bh_running = false; > - info->bh_requested = false; > - } > - > - spin_unlock_irqrestore(&info->lock, flags); > - > - return rc; > -} > - > -static void bh_handler(struct work_struct *work) > -{ > - MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task); > - struct tty_struct *tty; > - int action; > - > - if (debug_level >= DEBUG_LEVEL_BH) > - printk("%s(%d):bh_handler(%s) entry\n", > - __FILE__,__LINE__,info->device_name); > - > - info->bh_running = true; > - tty = tty_port_tty_get(&info->port); > - > - while((action = bh_action(info)) != 0) { > - > - /* Process work item */ > - if (debug_level >= DEBUG_LEVEL_BH) > - printk("%s(%d):bh_handler() work item action=%d\n", > - __FILE__,__LINE__,action); > - > - switch (action) { > - > - case BH_RECEIVE: > - while(rx_get_frame(info, tty)); > - break; > - case BH_TRANSMIT: > - bh_transmit(info, tty); > - break; > - case BH_STATUS: > - bh_status(info); > - break; > - default: > - /* unknown work item ID */ > - printk("Unknown work item ID=%08X!\n", action); > - break; > - } > - } > - > - tty_kref_put(tty); > - if (debug_level >= DEBUG_LEVEL_BH) > - printk("%s(%d):bh_handler(%s) exit\n", > - __FILE__,__LINE__,info->device_name); > -} > - > -static void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty) > -{ > - if (debug_level >= DEBUG_LEVEL_BH) > - printk("bh_transmit() entry on %s\n", info->device_name); > - > - if (tty) > - tty_wakeup(tty); > -} > - > -static void bh_status(MGSLPC_INFO *info) > -{ > - info->ri_chkcount = 0; > - info->dsr_chkcount = 0; > - info->dcd_chkcount = 0; > - info->cts_chkcount = 0; > -} > - > -/* eom: non-zero = end of frame */ > -static void rx_ready_hdlc(MGSLPC_INFO *info, int eom) > -{ > - unsigned char data[2]; > - unsigned char fifo_count, read_count, i; > - RXBUF *buf = (RXBUF*)(info->rx_buf + (info->rx_put * info->rx_buf_size)); > - > - if (debug_level >= DEBUG_LEVEL_ISR) > - printk("%s(%d):rx_ready_hdlc(eom=%d)\n", __FILE__, __LINE__, eom); > - > - if (!info->rx_enabled) > - return; > - > - if (info->rx_frame_count >= info->rx_buf_count) { > - /* no more free buffers */ > - issue_command(info, CHA, CMD_RXRESET); > - info->pending_bh |= BH_RECEIVE; > - info->rx_overflow = true; > - info->icount.buf_overrun++; > - return; > - } > - > - if (eom) { > - /* end of frame, get FIFO count from RBCL register */ > - fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f); > - if (fifo_count == 0) > - fifo_count = 32; > - } else > - fifo_count = 32; > - > - do { > - if (fifo_count == 1) { > - read_count = 1; > - data[0] = read_reg(info, CHA + RXFIFO); > - } else { > - read_count = 2; > - *((unsigned short *) data) = read_reg16(info, CHA + RXFIFO); > - } > - fifo_count -= read_count; > - if (!fifo_count && eom) > - buf->status = data[--read_count]; > - > - for (i = 0; i < read_count; i++) { > - if (buf->count >= info->max_frame_size) { > - /* frame too large, reset receiver and reset current buffer */ > - issue_command(info, CHA, CMD_RXRESET); > - buf->count = 0; > - return; > - } > - *(buf->data + buf->count) = data[i]; > - buf->count++; > - } > - } while (fifo_count); > - > - if (eom) { > - info->pending_bh |= BH_RECEIVE; > - info->rx_frame_count++; > - info->rx_put++; > - if (info->rx_put >= info->rx_buf_count) > - info->rx_put = 0; > - } > - issue_command(info, CHA, CMD_RXFIFO); > -} > - > -static void rx_ready_async(MGSLPC_INFO *info, int tcd) > -{ > - struct tty_port *port = &info->port; > - unsigned char data, status, flag; > - int fifo_count; > - int work = 0; > - struct mgsl_icount *icount = &info->icount; > - > - if (tcd) { > - /* early termination, get FIFO count from RBCL register */ > - fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f); > - > - /* Zero fifo count could mean 0 or 32 bytes available. > - * If BIT5 of STAR is set then at least 1 byte is available. > - */ > - if (!fifo_count && (read_reg(info,CHA+STAR) & BIT5)) > - fifo_count = 32; > - } else > - fifo_count = 32; > - > - tty_buffer_request_room(port, fifo_count); > - /* Flush received async data to receive data buffer. */ > - while (fifo_count) { > - data = read_reg(info, CHA + RXFIFO); > - status = read_reg(info, CHA + RXFIFO); > - fifo_count -= 2; > - > - icount->rx++; > - flag = TTY_NORMAL; > - > - // if no frameing/crc error then save data > - // BIT7:parity error > - // BIT6:framing error > - > - if (status & (BIT7 | BIT6)) { > - if (status & BIT7) > - icount->parity++; > - else > - icount->frame++; > - > - /* discard char if tty control flags say so */ > - if (status & info->ignore_status_mask) > - continue; > - > - status &= info->read_status_mask; > - > - if (status & BIT7) > - flag = TTY_PARITY; > - else if (status & BIT6) > - flag = TTY_FRAME; > - } > - work += tty_insert_flip_char(port, data, flag); > - } > - issue_command(info, CHA, CMD_RXFIFO); > - > - if (debug_level >= DEBUG_LEVEL_ISR) { > - printk("%s(%d):rx_ready_async", > - __FILE__,__LINE__); > - printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n", > - __FILE__,__LINE__,icount->rx,icount->brk, > - icount->parity,icount->frame,icount->overrun); > - } > - > - if (work) > - tty_flip_buffer_push(port); > -} > - > - > -static void tx_done(MGSLPC_INFO *info, struct tty_struct *tty) > -{ > - if (!info->tx_active) > - return; > - > - info->tx_active = false; > - info->tx_aborting = false; > - > - if (info->params.mode == MGSL_MODE_ASYNC) > - return; > - > - info->tx_count = info->tx_put = info->tx_get = 0; > - del_timer(&info->tx_timer); > - > - if (info->drop_rts_on_tx_done) { > - get_signals(info); > - if (info->serial_signals & SerialSignal_RTS) { > - info->serial_signals &= ~SerialSignal_RTS; > - set_signals(info); > - } > - info->drop_rts_on_tx_done = false; > - } > - > -#if SYNCLINK_GENERIC_HDLC > - if (info->netcount) > - hdlcdev_tx_done(info); > - else > -#endif > - { > - if (tty && (tty->flow.stopped || tty->hw_stopped)) { > - tx_stop(info); > - return; > - } > - info->pending_bh |= BH_TRANSMIT; > - } > -} > - > -static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty) > -{ > - unsigned char fifo_count = 32; > - int c; > - > - if (debug_level >= DEBUG_LEVEL_ISR) > - printk("%s(%d):tx_ready(%s)\n", __FILE__, __LINE__, info->device_name); > - > - if (info->params.mode == MGSL_MODE_HDLC) { > - if (!info->tx_active) > - return; > - } else { > - if (tty && (tty->flow.stopped || tty->hw_stopped)) { > - tx_stop(info); > - return; > - } > - if (!info->tx_count) > - info->tx_active = false; > - } > - > - if (!info->tx_count) > - return; > - > - while (info->tx_count && fifo_count) { > - c = min(2, min_t(int, fifo_count, min(info->tx_count, TXBUFSIZE - info->tx_get))); > - > - if (c == 1) { > - write_reg(info, CHA + TXFIFO, *(info->tx_buf + info->tx_get)); > - } else { > - write_reg16(info, CHA + TXFIFO, > - *((unsigned short*)(info->tx_buf + info->tx_get))); > - } > - info->tx_count -= c; > - info->tx_get = (info->tx_get + c) & (TXBUFSIZE - 1); > - fifo_count -= c; > - } > - > - if (info->params.mode == MGSL_MODE_ASYNC) { > - if (info->tx_count < WAKEUP_CHARS) > - info->pending_bh |= BH_TRANSMIT; > - issue_command(info, CHA, CMD_TXFIFO); > - } else { > - if (info->tx_count) > - issue_command(info, CHA, CMD_TXFIFO); > - else > - issue_command(info, CHA, CMD_TXFIFO + CMD_TXEOM); > - } > -} > - > -static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty) > -{ > - get_signals(info); > - if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) > - irq_disable(info, CHB, IRQ_CTS); > - info->icount.cts++; > - if (info->serial_signals & SerialSignal_CTS) > - info->input_signal_events.cts_up++; > - else > - info->input_signal_events.cts_down++; > - wake_up_interruptible(&info->status_event_wait_q); > - wake_up_interruptible(&info->event_wait_q); > - > - if (tty && tty_port_cts_enabled(&info->port)) { > - if (tty->hw_stopped) { > - if (info->serial_signals & SerialSignal_CTS) { > - if (debug_level >= DEBUG_LEVEL_ISR) > - printk("CTS tx start..."); > - tty->hw_stopped = 0; > - tx_start(info, tty); > - info->pending_bh |= BH_TRANSMIT; > - return; > - } > - } else { > - if (!(info->serial_signals & SerialSignal_CTS)) { > - if (debug_level >= DEBUG_LEVEL_ISR) > - printk("CTS tx stop..."); > - tty->hw_stopped = 1; > - tx_stop(info); > - } > - } > - } > - info->pending_bh |= BH_STATUS; > -} > - > -static void dcd_change(MGSLPC_INFO *info, struct tty_struct *tty) > -{ > - get_signals(info); > - if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) > - irq_disable(info, CHB, IRQ_DCD); > - info->icount.dcd++; > - if (info->serial_signals & SerialSignal_DCD) { > - info->input_signal_events.dcd_up++; > - } > - else > - info->input_signal_events.dcd_down++; > -#if SYNCLINK_GENERIC_HDLC > - if (info->netcount) { > - if (info->serial_signals & SerialSignal_DCD) > - netif_carrier_on(info->netdev); > - else > - netif_carrier_off(info->netdev); > - } > -#endif > - wake_up_interruptible(&info->status_event_wait_q); > - wake_up_interruptible(&info->event_wait_q); > - > - if (tty_port_check_carrier(&info->port)) { > - if (debug_level >= DEBUG_LEVEL_ISR) > - printk("%s CD now %s...", info->device_name, > - (info->serial_signals & SerialSignal_DCD) ? "on" : "off"); > - if (info->serial_signals & SerialSignal_DCD) > - wake_up_interruptible(&info->port.open_wait); > - else { > - if (debug_level >= DEBUG_LEVEL_ISR) > - printk("doing serial hangup..."); > - if (tty) > - tty_hangup(tty); > - } > - } > - info->pending_bh |= BH_STATUS; > -} > - > -static void dsr_change(MGSLPC_INFO *info) > -{ > - get_signals(info); > - if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) > - port_irq_disable(info, PVR_DSR); > - info->icount.dsr++; > - if (info->serial_signals & SerialSignal_DSR) > - info->input_signal_events.dsr_up++; > - else > - info->input_signal_events.dsr_down++; > - wake_up_interruptible(&info->status_event_wait_q); > - wake_up_interruptible(&info->event_wait_q); > - info->pending_bh |= BH_STATUS; > -} > - > -static void ri_change(MGSLPC_INFO *info) > -{ > - get_signals(info); > - if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) > - port_irq_disable(info, PVR_RI); > - info->icount.rng++; > - if (info->serial_signals & SerialSignal_RI) > - info->input_signal_events.ri_up++; > - else > - info->input_signal_events.ri_down++; > - wake_up_interruptible(&info->status_event_wait_q); > - wake_up_interruptible(&info->event_wait_q); > - info->pending_bh |= BH_STATUS; > -} > - > -/* Interrupt service routine entry point. > - * > - * Arguments: > - * > - * irq interrupt number that caused interrupt > - * dev_id device ID supplied during interrupt registration > - */ > -static irqreturn_t mgslpc_isr(int dummy, void *dev_id) > -{ > - MGSLPC_INFO *info = dev_id; > - struct tty_struct *tty; > - unsigned short isr; > - unsigned char gis, pis; > - int count=0; > - > - if (debug_level >= DEBUG_LEVEL_ISR) > - printk("mgslpc_isr(%d) entry.\n", info->irq_level); > - > - if (!(info->p_dev->_locked)) > - return IRQ_HANDLED; > - > - tty = tty_port_tty_get(&info->port); > - > - spin_lock(&info->lock); > - > - while ((gis = read_reg(info, CHA + GIS))) { > - if (debug_level >= DEBUG_LEVEL_ISR) > - printk("mgslpc_isr %s gis=%04X\n", info->device_name,gis); > - > - if ((gis & 0x70) || count > 1000) { > - printk("synclink_cs:hardware failed or ejected\n"); > - break; > - } > - count++; > - > - if (gis & (BIT1 | BIT0)) { > - isr = read_reg16(info, CHB + ISR); > - if (isr & IRQ_DCD) > - dcd_change(info, tty); > - if (isr & IRQ_CTS) > - cts_change(info, tty); > - } > - if (gis & (BIT3 | BIT2)) > - { > - isr = read_reg16(info, CHA + ISR); > - if (isr & IRQ_TIMER) { > - info->irq_occurred = true; > - irq_disable(info, CHA, IRQ_TIMER); > - } > - > - /* receive IRQs */ > - if (isr & IRQ_EXITHUNT) { > - info->icount.exithunt++; > - wake_up_interruptible(&info->event_wait_q); > - } > - if (isr & IRQ_BREAK_ON) { > - info->icount.brk++; > - if (info->port.flags & ASYNC_SAK) > - do_SAK(tty); > - } > - if (isr & IRQ_RXTIME) { > - issue_command(info, CHA, CMD_RXFIFO_READ); > - } > - if (isr & (IRQ_RXEOM | IRQ_RXFIFO)) { > - if (info->params.mode == MGSL_MODE_HDLC) > - rx_ready_hdlc(info, isr & IRQ_RXEOM); > - else > - rx_ready_async(info, isr & IRQ_RXEOM); > - } > - > - /* transmit IRQs */ > - if (isr & IRQ_UNDERRUN) { > - if (info->tx_aborting) > - info->icount.txabort++; > - else > - info->icount.txunder++; > - tx_done(info, tty); > - } > - else if (isr & IRQ_ALLSENT) { > - info->icount.txok++; > - tx_done(info, tty); > - } > - else if (isr & IRQ_TXFIFO) > - tx_ready(info, tty); > - } > - if (gis & BIT7) { > - pis = read_reg(info, CHA + PIS); > - if (pis & BIT1) > - dsr_change(info); > - if (pis & BIT2) > - ri_change(info); > - } > - } > - > - /* Request bottom half processing if there's something > - * for it to do and the bh is not already running > - */ > - > - if (info->pending_bh && !info->bh_running && !info->bh_requested) { > - if (debug_level >= DEBUG_LEVEL_ISR) > - printk("%s(%d):%s queueing bh task.\n", > - __FILE__,__LINE__,info->device_name); > - schedule_work(&info->task); > - info->bh_requested = true; > - } > - > - spin_unlock(&info->lock); > - tty_kref_put(tty); > - > - if (debug_level >= DEBUG_LEVEL_ISR) > - printk("%s(%d):mgslpc_isr(%d)exit.\n", > - __FILE__, __LINE__, info->irq_level); > - > - return IRQ_HANDLED; > -} > - > -/* Initialize and start device. > - */ > -static int startup(MGSLPC_INFO * info, struct tty_struct *tty) > -{ > - int retval = 0; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):startup(%s)\n", __FILE__, __LINE__, info->device_name); > - > - if (tty_port_initialized(&info->port)) > - return 0; > - > - if (!info->tx_buf) { > - /* allocate a page of memory for a transmit buffer */ > - info->tx_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); > - if (!info->tx_buf) { > - printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n", > - __FILE__, __LINE__, info->device_name); > - return -ENOMEM; > - } > - } > - > - info->pending_bh = 0; > - > - memset(&info->icount, 0, sizeof(info->icount)); > - > - timer_setup(&info->tx_timer, tx_timeout, 0); > - > - /* Allocate and claim adapter resources */ > - retval = claim_resources(info); > - > - /* perform existence check and diagnostics */ > - if (!retval) > - retval = adapter_test(info); > - > - if (retval) { > - if (capable(CAP_SYS_ADMIN) && tty) > - set_bit(TTY_IO_ERROR, &tty->flags); > - release_resources(info); > - return retval; > - } > - > - /* program hardware for current parameters */ > - mgslpc_change_params(info, tty); > - > - if (tty) > - clear_bit(TTY_IO_ERROR, &tty->flags); > - > - tty_port_set_initialized(&info->port, true); > - > - return 0; > -} > - > -/* Called by mgslpc_close() and mgslpc_hangup() to shutdown hardware > - */ > -static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty) > -{ > - unsigned long flags; > - > - if (!tty_port_initialized(&info->port)) > - return; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_shutdown(%s)\n", > - __FILE__, __LINE__, info->device_name); > - > - /* clear status wait queue because status changes */ > - /* can't happen after shutting down the hardware */ > - wake_up_interruptible(&info->status_event_wait_q); > - wake_up_interruptible(&info->event_wait_q); > - > - del_timer_sync(&info->tx_timer); > - > - if (info->tx_buf) { > - free_page((unsigned long) info->tx_buf); > - info->tx_buf = NULL; > - } > - > - spin_lock_irqsave(&info->lock, flags); > - > - rx_stop(info); > - tx_stop(info); > - > - /* TODO:disable interrupts instead of reset to preserve signal states */ > - reset_device(info); > - > - if (!tty || C_HUPCL(tty)) { > - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); > - set_signals(info); > - } > - > - spin_unlock_irqrestore(&info->lock, flags); > - > - release_resources(info); > - > - if (tty) > - set_bit(TTY_IO_ERROR, &tty->flags); > - > - tty_port_set_initialized(&info->port, false); > -} > - > -static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty) > -{ > - unsigned long flags; > - > - spin_lock_irqsave(&info->lock, flags); > - > - rx_stop(info); > - tx_stop(info); > - info->tx_count = info->tx_put = info->tx_get = 0; > - > - if (info->params.mode == MGSL_MODE_HDLC || info->netcount) > - hdlc_mode(info); > - else > - async_mode(info); > - > - set_signals(info); > - > - info->dcd_chkcount = 0; > - info->cts_chkcount = 0; > - info->ri_chkcount = 0; > - info->dsr_chkcount = 0; > - > - irq_enable(info, CHB, IRQ_DCD | IRQ_CTS); > - port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI); > - get_signals(info); > - > - if (info->netcount || (tty && C_CREAD(tty))) > - rx_start(info); > - > - spin_unlock_irqrestore(&info->lock, flags); > -} > - > -/* Reconfigure adapter based on new parameters > - */ > -static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty) > -{ > - unsigned cflag; > - int bits_per_char; > - > - if (!tty) > - return; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_change_params(%s)\n", > - __FILE__, __LINE__, info->device_name); > - > - cflag = tty->termios.c_cflag; > - > - /* if B0 rate (hangup) specified then negate RTS and DTR */ > - /* otherwise assert RTS and DTR */ > - if (cflag & CBAUD) > - info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; > - else > - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); > - > - /* byte size and parity */ > - if ((cflag & CSIZE) != CS8) { > - cflag &= ~CSIZE; > - cflag |= CS7; > - tty->termios.c_cflag = cflag; > - } > - info->params.data_bits = tty_get_char_size(cflag); > - > - if (cflag & CSTOPB) > - info->params.stop_bits = 2; > - else > - info->params.stop_bits = 1; > - > - info->params.parity = ASYNC_PARITY_NONE; > - if (cflag & PARENB) { > - if (cflag & PARODD) > - info->params.parity = ASYNC_PARITY_ODD; > - else > - info->params.parity = ASYNC_PARITY_EVEN; > - if (cflag & CMSPAR) > - info->params.parity = ASYNC_PARITY_SPACE; > - } > - > - /* calculate number of jiffies to transmit a full > - * FIFO (32 bytes) at specified data rate > - */ > - bits_per_char = info->params.data_bits + > - info->params.stop_bits + 1; > - > - /* if port data rate is set to 460800 or less then > - * allow tty settings to override, otherwise keep the > - * current data rate. > - */ > - if (info->params.data_rate <= 460800) { > - info->params.data_rate = tty_get_baud_rate(tty); > - } > - > - if (info->params.data_rate) { > - info->timeout = (32*HZ*bits_per_char) / > - info->params.data_rate; > - } > - info->timeout += HZ/50; /* Add .02 seconds of slop */ > - > - tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); > - tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL); > - > - /* process tty input control flags */ > - > - info->read_status_mask = 0; > - if (I_INPCK(tty)) > - info->read_status_mask |= BIT7 | BIT6; > - if (I_IGNPAR(tty)) > - info->ignore_status_mask |= BIT7 | BIT6; > - > - mgslpc_program_hw(info, tty); > -} > - > -/* Add a character to the transmit buffer > - */ > -static int mgslpc_put_char(struct tty_struct *tty, unsigned char ch) > -{ > - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) { > - printk("%s(%d):mgslpc_put_char(%d) on %s\n", > - __FILE__, __LINE__, ch, info->device_name); > - } > - > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char")) > - return 0; > - > - if (!info->tx_buf) > - return 0; > - > - spin_lock_irqsave(&info->lock, flags); > - > - if (info->params.mode == MGSL_MODE_ASYNC || !info->tx_active) { > - if (info->tx_count < TXBUFSIZE - 1) { > - info->tx_buf[info->tx_put++] = ch; > - info->tx_put &= TXBUFSIZE-1; > - info->tx_count++; > - } > - } > - > - spin_unlock_irqrestore(&info->lock, flags); > - return 1; > -} > - > -/* Enable transmitter so remaining characters in the > - * transmit buffer are sent. > - */ > -static void mgslpc_flush_chars(struct tty_struct *tty) > -{ > - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_flush_chars() entry on %s tx_count=%d\n", > - __FILE__, __LINE__, info->device_name, info->tx_count); > - > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_chars")) > - return; > - > - if (info->tx_count <= 0 || tty->flow.stopped || > - tty->hw_stopped || !info->tx_buf) > - return; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_flush_chars() entry on %s starting transmitter\n", > - __FILE__, __LINE__, info->device_name); > - > - spin_lock_irqsave(&info->lock, flags); > - if (!info->tx_active) > - tx_start(info, tty); > - spin_unlock_irqrestore(&info->lock, flags); > -} > - > -/* Send a block of data > - * > - * Arguments: > - * > - * tty pointer to tty information structure > - * buf pointer to buffer containing send data > - * count size of send data in bytes > - * > - * Returns: number of characters written > - */ > -static int mgslpc_write(struct tty_struct * tty, > - const unsigned char *buf, int count) > -{ > - int c, ret = 0; > - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_write(%s) count=%d\n", > - __FILE__, __LINE__, info->device_name, count); > - > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write") || > - !info->tx_buf) > - goto cleanup; > - > - if (info->params.mode == MGSL_MODE_HDLC) { > - if (count > TXBUFSIZE) { > - ret = -EIO; > - goto cleanup; > - } > - if (info->tx_active) > - goto cleanup; > - else if (info->tx_count) > - goto start; > - } > - > - for (;;) { > - c = min(count, > - min(TXBUFSIZE - info->tx_count - 1, > - TXBUFSIZE - info->tx_put)); > - if (c <= 0) > - break; > - > - memcpy(info->tx_buf + info->tx_put, buf, c); > - > - spin_lock_irqsave(&info->lock, flags); > - info->tx_put = (info->tx_put + c) & (TXBUFSIZE-1); > - info->tx_count += c; > - spin_unlock_irqrestore(&info->lock, flags); > - > - buf += c; > - count -= c; > - ret += c; > - } > -start: > - if (info->tx_count && !tty->flow.stopped && !tty->hw_stopped) { > - spin_lock_irqsave(&info->lock, flags); > - if (!info->tx_active) > - tx_start(info, tty); > - spin_unlock_irqrestore(&info->lock, flags); > - } > -cleanup: > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_write(%s) returning=%d\n", > - __FILE__, __LINE__, info->device_name, ret); > - return ret; > -} > - > -/* Return the count of free bytes in transmit buffer > - */ > -static unsigned int mgslpc_write_room(struct tty_struct *tty) > -{ > - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; > - int ret; > - > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write_room")) > - return 0; > - > - if (info->params.mode == MGSL_MODE_HDLC) { > - /* HDLC (frame oriented) mode */ > - if (info->tx_active) > - return 0; > - else > - return HDLC_MAX_FRAME_SIZE; > - } else { > - ret = TXBUFSIZE - info->tx_count - 1; > - if (ret < 0) > - ret = 0; > - } > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_write_room(%s)=%d\n", > - __FILE__, __LINE__, info->device_name, ret); > - return ret; > -} > - > -/* Return the count of bytes in transmit buffer > - */ > -static unsigned int mgslpc_chars_in_buffer(struct tty_struct *tty) > -{ > - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; > - unsigned int rc; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_chars_in_buffer(%s)\n", > - __FILE__, __LINE__, info->device_name); > - > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_chars_in_buffer")) > - return 0; > - > - if (info->params.mode == MGSL_MODE_HDLC) > - rc = info->tx_active ? info->max_frame_size : 0; > - else > - rc = info->tx_count; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_chars_in_buffer(%s)=%u\n", > - __FILE__, __LINE__, info->device_name, rc); > - > - return rc; > -} > - > -/* Discard all data in the send buffer > - */ > -static void mgslpc_flush_buffer(struct tty_struct *tty) > -{ > - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_flush_buffer(%s) entry\n", > - __FILE__, __LINE__, info->device_name); > - > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_buffer")) > - return; > - > - spin_lock_irqsave(&info->lock, flags); > - info->tx_count = info->tx_put = info->tx_get = 0; > - del_timer(&info->tx_timer); > - spin_unlock_irqrestore(&info->lock, flags); > - > - wake_up_interruptible(&tty->write_wait); > - tty_wakeup(tty); > -} > - > -/* Send a high-priority XON/XOFF character > - */ > -static void mgslpc_send_xchar(struct tty_struct *tty, char ch) > -{ > - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_send_xchar(%s,%d)\n", > - __FILE__, __LINE__, info->device_name, ch); > - > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_send_xchar")) > - return; > - > - info->x_char = ch; > - if (ch) { > - spin_lock_irqsave(&info->lock, flags); > - if (!info->tx_enabled) > - tx_start(info, tty); > - spin_unlock_irqrestore(&info->lock, flags); > - } > -} > - > -/* Signal remote device to throttle send data (our receive data) > - */ > -static void mgslpc_throttle(struct tty_struct * tty) > -{ > - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_throttle(%s) entry\n", > - __FILE__, __LINE__, info->device_name); > - > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_throttle")) > - return; > - > - if (I_IXOFF(tty)) > - mgslpc_send_xchar(tty, STOP_CHAR(tty)); > - > - if (C_CRTSCTS(tty)) { > - spin_lock_irqsave(&info->lock, flags); > - info->serial_signals &= ~SerialSignal_RTS; > - set_signals(info); > - spin_unlock_irqrestore(&info->lock, flags); > - } > -} > - > -/* Signal remote device to stop throttling send data (our receive data) > - */ > -static void mgslpc_unthrottle(struct tty_struct * tty) > -{ > - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_unthrottle(%s) entry\n", > - __FILE__, __LINE__, info->device_name); > - > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_unthrottle")) > - return; > - > - if (I_IXOFF(tty)) { > - if (info->x_char) > - info->x_char = 0; > - else > - mgslpc_send_xchar(tty, START_CHAR(tty)); > - } > - > - if (C_CRTSCTS(tty)) { > - spin_lock_irqsave(&info->lock, flags); > - info->serial_signals |= SerialSignal_RTS; > - set_signals(info); > - spin_unlock_irqrestore(&info->lock, flags); > - } > -} > - > -/* get the current serial statistics > - */ > -static int get_stats(MGSLPC_INFO * info, struct mgsl_icount __user *user_icount) > -{ > - int err; > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("get_params(%s)\n", info->device_name); > - if (!user_icount) { > - memset(&info->icount, 0, sizeof(info->icount)); > - } else { > - COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); > - if (err) > - return -EFAULT; > - } > - return 0; > -} > - > -/* get the current serial parameters > - */ > -static int get_params(MGSLPC_INFO * info, MGSL_PARAMS __user *user_params) > -{ > - int err; > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("get_params(%s)\n", info->device_name); > - COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS)); > - if (err) > - return -EFAULT; > - return 0; > -} > - > -/* set the serial parameters > - * > - * Arguments: > - * > - * info pointer to device instance data > - * new_params user buffer containing new serial params > - * > - * Returns: 0 if success, otherwise error code > - */ > -static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params, struct tty_struct *tty) > -{ > - unsigned long flags; > - MGSL_PARAMS tmp_params; > - int err; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):set_params %s\n", __FILE__,__LINE__, > - info->device_name); > - COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS)); > - if (err) { > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):set_params(%s) user buffer copy failed\n", > - __FILE__, __LINE__, info->device_name); > - return -EFAULT; > - } > - > - spin_lock_irqsave(&info->lock, flags); > - memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); > - spin_unlock_irqrestore(&info->lock, flags); > - > - mgslpc_change_params(info, tty); > - > - return 0; > -} > - > -static int get_txidle(MGSLPC_INFO * info, int __user *idle_mode) > -{ > - int err; > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("get_txidle(%s)=%d\n", info->device_name, info->idle_mode); > - COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int)); > - if (err) > - return -EFAULT; > - return 0; > -} > - > -static int set_txidle(MGSLPC_INFO * info, int idle_mode) > -{ > - unsigned long flags; > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("set_txidle(%s,%d)\n", info->device_name, idle_mode); > - spin_lock_irqsave(&info->lock, flags); > - info->idle_mode = idle_mode; > - tx_set_idle(info); > - spin_unlock_irqrestore(&info->lock, flags); > - return 0; > -} > - > -static int get_interface(MGSLPC_INFO * info, int __user *if_mode) > -{ > - int err; > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("get_interface(%s)=%d\n", info->device_name, info->if_mode); > - COPY_TO_USER(err,if_mode, &info->if_mode, sizeof(int)); > - if (err) > - return -EFAULT; > - return 0; > -} > - > -static int set_interface(MGSLPC_INFO * info, int if_mode) > -{ > - unsigned long flags; > - unsigned char val; > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("set_interface(%s,%d)\n", info->device_name, if_mode); > - spin_lock_irqsave(&info->lock, flags); > - info->if_mode = if_mode; > - > - val = read_reg(info, PVR) & 0x0f; > - switch (info->if_mode) > - { > - case MGSL_INTERFACE_RS232: val |= PVR_RS232; break; > - case MGSL_INTERFACE_V35: val |= PVR_V35; break; > - case MGSL_INTERFACE_RS422: val |= PVR_RS422; break; > - } > - write_reg(info, PVR, val); > - > - spin_unlock_irqrestore(&info->lock, flags); > - return 0; > -} > - > -static int set_txenable(MGSLPC_INFO * info, int enable, struct tty_struct *tty) > -{ > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("set_txenable(%s,%d)\n", info->device_name, enable); > - > - spin_lock_irqsave(&info->lock, flags); > - if (enable) { > - if (!info->tx_enabled) > - tx_start(info, tty); > - } else { > - if (info->tx_enabled) > - tx_stop(info); > - } > - spin_unlock_irqrestore(&info->lock, flags); > - return 0; > -} > - > -static int tx_abort(MGSLPC_INFO * info) > -{ > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("tx_abort(%s)\n", info->device_name); > - > - spin_lock_irqsave(&info->lock, flags); > - if (info->tx_active && info->tx_count && > - info->params.mode == MGSL_MODE_HDLC) { > - /* clear data count so FIFO is not filled on next IRQ. > - * This results in underrun and abort transmission. > - */ > - info->tx_count = info->tx_put = info->tx_get = 0; > - info->tx_aborting = true; > - } > - spin_unlock_irqrestore(&info->lock, flags); > - return 0; > -} > - > -static int set_rxenable(MGSLPC_INFO * info, int enable) > -{ > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("set_rxenable(%s,%d)\n", info->device_name, enable); > - > - spin_lock_irqsave(&info->lock, flags); > - if (enable) { > - if (!info->rx_enabled) > - rx_start(info); > - } else { > - if (info->rx_enabled) > - rx_stop(info); > - } > - spin_unlock_irqrestore(&info->lock, flags); > - return 0; > -} > - > -/* wait for specified event to occur > - * > - * Arguments: info pointer to device instance data > - * mask pointer to bitmask of events to wait for > - * Return Value: 0 if successful and bit mask updated with > - * of events triggerred, > - * otherwise error code > - */ > -static int wait_events(MGSLPC_INFO * info, int __user *mask_ptr) > -{ > - unsigned long flags; > - int s; > - int rc=0; > - struct mgsl_icount cprev, cnow; > - int events; > - int mask; > - struct _input_signal_events oldsigs, newsigs; > - DECLARE_WAITQUEUE(wait, current); > - > - COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int)); > - if (rc) > - return -EFAULT; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("wait_events(%s,%d)\n", info->device_name, mask); > - > - spin_lock_irqsave(&info->lock, flags); > - > - /* return immediately if state matches requested events */ > - get_signals(info); > - s = info->serial_signals; > - events = mask & > - ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + > - ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) + > - ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) + > - ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) ); > - if (events) { > - spin_unlock_irqrestore(&info->lock, flags); > - goto exit; > - } > - > - /* save current irq counts */ > - cprev = info->icount; > - oldsigs = info->input_signal_events; > - > - if ((info->params.mode == MGSL_MODE_HDLC) && > - (mask & MgslEvent_ExitHuntMode)) > - irq_enable(info, CHA, IRQ_EXITHUNT); > - > - set_current_state(TASK_INTERRUPTIBLE); > - add_wait_queue(&info->event_wait_q, &wait); > - > - spin_unlock_irqrestore(&info->lock, flags); > - > - > - for(;;) { > - schedule(); > - if (signal_pending(current)) { > - rc = -ERESTARTSYS; > - break; > - } > - > - /* get current irq counts */ > - spin_lock_irqsave(&info->lock, flags); > - cnow = info->icount; > - newsigs = info->input_signal_events; > - set_current_state(TASK_INTERRUPTIBLE); > - spin_unlock_irqrestore(&info->lock, flags); > - > - /* if no change, wait aborted for some reason */ > - if (newsigs.dsr_up == oldsigs.dsr_up && > - newsigs.dsr_down == oldsigs.dsr_down && > - newsigs.dcd_up == oldsigs.dcd_up && > - newsigs.dcd_down == oldsigs.dcd_down && > - newsigs.cts_up == oldsigs.cts_up && > - newsigs.cts_down == oldsigs.cts_down && > - newsigs.ri_up == oldsigs.ri_up && > - newsigs.ri_down == oldsigs.ri_down && > - cnow.exithunt == cprev.exithunt && > - cnow.rxidle == cprev.rxidle) { > - rc = -EIO; > - break; > - } > - > - events = mask & > - ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) + > - (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) + > - (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) + > - (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) + > - (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) + > - (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) + > - (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) + > - (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) + > - (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) + > - (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) ); > - if (events) > - break; > - > - cprev = cnow; > - oldsigs = newsigs; > - } > - > - remove_wait_queue(&info->event_wait_q, &wait); > - set_current_state(TASK_RUNNING); > - > - if (mask & MgslEvent_ExitHuntMode) { > - spin_lock_irqsave(&info->lock, flags); > - if (!waitqueue_active(&info->event_wait_q)) > - irq_disable(info, CHA, IRQ_EXITHUNT); > - spin_unlock_irqrestore(&info->lock, flags); > - } > -exit: > - if (rc == 0) > - PUT_USER(rc, events, mask_ptr); > - return rc; > -} > - > -static int modem_input_wait(MGSLPC_INFO *info,int arg) > -{ > - unsigned long flags; > - int rc; > - struct mgsl_icount cprev, cnow; > - DECLARE_WAITQUEUE(wait, current); > - > - /* save current irq counts */ > - spin_lock_irqsave(&info->lock, flags); > - cprev = info->icount; > - add_wait_queue(&info->status_event_wait_q, &wait); > - set_current_state(TASK_INTERRUPTIBLE); > - spin_unlock_irqrestore(&info->lock, flags); > - > - for(;;) { > - schedule(); > - if (signal_pending(current)) { > - rc = -ERESTARTSYS; > - break; > - } > - > - /* get new irq counts */ > - spin_lock_irqsave(&info->lock, flags); > - cnow = info->icount; > - set_current_state(TASK_INTERRUPTIBLE); > - spin_unlock_irqrestore(&info->lock, flags); > - > - /* if no change, wait aborted for some reason */ > - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && > - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { > - rc = -EIO; > - break; > - } > - > - /* check for change in caller specified modem input */ > - if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) || > - (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) || > - (arg & TIOCM_CD && cnow.dcd != cprev.dcd) || > - (arg & TIOCM_CTS && cnow.cts != cprev.cts)) { > - rc = 0; > - break; > - } > - > - cprev = cnow; > - } > - remove_wait_queue(&info->status_event_wait_q, &wait); > - set_current_state(TASK_RUNNING); > - return rc; > -} > - > -/* return the state of the serial control and status signals > - */ > -static int tiocmget(struct tty_struct *tty) > -{ > - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; > - unsigned int result; > - unsigned long flags; > - > - spin_lock_irqsave(&info->lock, flags); > - get_signals(info); > - spin_unlock_irqrestore(&info->lock, flags); > - > - result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS:0) + > - ((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR:0) + > - ((info->serial_signals & SerialSignal_DCD) ? TIOCM_CAR:0) + > - ((info->serial_signals & SerialSignal_RI) ? TIOCM_RNG:0) + > - ((info->serial_signals & SerialSignal_DSR) ? TIOCM_DSR:0) + > - ((info->serial_signals & SerialSignal_CTS) ? TIOCM_CTS:0); > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):%s tiocmget() value=%08X\n", > - __FILE__, __LINE__, info->device_name, result); > - return result; > -} > - > -/* set modem control signals (DTR/RTS) > - */ > -static int tiocmset(struct tty_struct *tty, > - unsigned int set, unsigned int clear) > -{ > - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):%s tiocmset(%x,%x)\n", > - __FILE__, __LINE__, info->device_name, set, clear); > - > - if (set & TIOCM_RTS) > - info->serial_signals |= SerialSignal_RTS; > - if (set & TIOCM_DTR) > - info->serial_signals |= SerialSignal_DTR; > - if (clear & TIOCM_RTS) > - info->serial_signals &= ~SerialSignal_RTS; > - if (clear & TIOCM_DTR) > - info->serial_signals &= ~SerialSignal_DTR; > - > - spin_lock_irqsave(&info->lock, flags); > - set_signals(info); > - spin_unlock_irqrestore(&info->lock, flags); > - > - return 0; > -} > - > -/* Set or clear transmit break condition > - * > - * Arguments: tty pointer to tty instance data > - * break_state -1=set break condition, 0=clear > - */ > -static int mgslpc_break(struct tty_struct *tty, int break_state) > -{ > - MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_break(%s,%d)\n", > - __FILE__, __LINE__, info->device_name, break_state); > - > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_break")) > - return -EINVAL; > - > - spin_lock_irqsave(&info->lock, flags); > - if (break_state == -1) > - set_reg_bits(info, CHA+DAFO, BIT6); > - else > - clear_reg_bits(info, CHA+DAFO, BIT6); > - spin_unlock_irqrestore(&info->lock, flags); > - return 0; > -} > - > -static int mgslpc_get_icount(struct tty_struct *tty, > - struct serial_icounter_struct *icount) > -{ > - MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; > - struct mgsl_icount cnow; /* kernel counter temps */ > - unsigned long flags; > - > - spin_lock_irqsave(&info->lock, flags); > - cnow = info->icount; > - spin_unlock_irqrestore(&info->lock, flags); > - > - icount->cts = cnow.cts; > - icount->dsr = cnow.dsr; > - icount->rng = cnow.rng; > - icount->dcd = cnow.dcd; > - icount->rx = cnow.rx; > - icount->tx = cnow.tx; > - icount->frame = cnow.frame; > - icount->overrun = cnow.overrun; > - icount->parity = cnow.parity; > - icount->brk = cnow.brk; > - icount->buf_overrun = cnow.buf_overrun; > - > - return 0; > -} > - > -/* Service an IOCTL request > - * > - * Arguments: > - * > - * tty pointer to tty instance data > - * cmd IOCTL command code > - * arg command argument/context > - * > - * Return Value: 0 if success, otherwise error code > - */ > -static int mgslpc_ioctl(struct tty_struct *tty, > - unsigned int cmd, unsigned long arg) > -{ > - MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; > - void __user *argp = (void __user *)arg; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__, __LINE__, > - info->device_name, cmd); > - > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_ioctl")) > - return -ENODEV; > - > - if (cmd != TIOCMIWAIT) { > - if (tty_io_error(tty)) > - return -EIO; > - } > - > - switch (cmd) { > - case MGSL_IOCGPARAMS: > - return get_params(info, argp); > - case MGSL_IOCSPARAMS: > - return set_params(info, argp, tty); > - case MGSL_IOCGTXIDLE: > - return get_txidle(info, argp); > - case MGSL_IOCSTXIDLE: > - return set_txidle(info, (int)arg); > - case MGSL_IOCGIF: > - return get_interface(info, argp); > - case MGSL_IOCSIF: > - return set_interface(info,(int)arg); > - case MGSL_IOCTXENABLE: > - return set_txenable(info,(int)arg, tty); > - case MGSL_IOCRXENABLE: > - return set_rxenable(info,(int)arg); > - case MGSL_IOCTXABORT: > - return tx_abort(info); > - case MGSL_IOCGSTATS: > - return get_stats(info, argp); > - case MGSL_IOCWAITEVENT: > - return wait_events(info, argp); > - case TIOCMIWAIT: > - return modem_input_wait(info,(int)arg); > - default: > - return -ENOIOCTLCMD; > - } > - return 0; > -} > - > -/* Set new termios settings > - * > - * Arguments: > - * > - * tty pointer to tty structure > - * termios pointer to buffer to hold returned old termios > - */ > -static void mgslpc_set_termios(struct tty_struct *tty, > - const struct ktermios *old_termios) > -{ > - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_set_termios %s\n", __FILE__, __LINE__, > - tty->driver->name); > - > - /* just return if nothing has changed */ > - if ((tty->termios.c_cflag == old_termios->c_cflag) > - && (RELEVANT_IFLAG(tty->termios.c_iflag) > - == RELEVANT_IFLAG(old_termios->c_iflag))) > - return; > - > - mgslpc_change_params(info, tty); > - > - /* Handle transition to B0 status */ > - if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) { > - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); > - spin_lock_irqsave(&info->lock, flags); > - set_signals(info); > - spin_unlock_irqrestore(&info->lock, flags); > - } > - > - /* Handle transition away from B0 status */ > - if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { > - info->serial_signals |= SerialSignal_DTR; > - if (!C_CRTSCTS(tty) || !tty_throttled(tty)) > - info->serial_signals |= SerialSignal_RTS; > - spin_lock_irqsave(&info->lock, flags); > - set_signals(info); > - spin_unlock_irqrestore(&info->lock, flags); > - } > - > - /* Handle turning off CRTSCTS */ > - if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) { > - tty->hw_stopped = 0; > - tx_release(tty); > - } > -} > - > -static void mgslpc_close(struct tty_struct *tty, struct file * filp) > -{ > - MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; > - struct tty_port *port = &info->port; > - > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_close")) > - return; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_close(%s) entry, count=%d\n", > - __FILE__, __LINE__, info->device_name, port->count); > - > - if (tty_port_close_start(port, tty, filp) == 0) > - goto cleanup; > - > - if (tty_port_initialized(port)) > - mgslpc_wait_until_sent(tty, info->timeout); > - > - mgslpc_flush_buffer(tty); > - > - tty_ldisc_flush(tty); > - shutdown(info, tty); > - > - tty_port_close_end(port, tty); > - tty_port_tty_set(port, NULL); > -cleanup: > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_close(%s) exit, count=%d\n", __FILE__, __LINE__, > - tty->driver->name, port->count); > -} > - > -/* Wait until the transmitter is empty. > - */ > -static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout) > -{ > - MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; > - unsigned long orig_jiffies, char_time; > - > - if (!info) > - return; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_wait_until_sent(%s) entry\n", > - __FILE__, __LINE__, info->device_name); > - > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_wait_until_sent")) > - return; > - > - if (!tty_port_initialized(&info->port)) > - goto exit; > - > - orig_jiffies = jiffies; > - > - /* Set check interval to 1/5 of estimated time to > - * send a character, and make it at least 1. The check > - * interval should also be less than the timeout. > - * Note: use tight timings here to satisfy the NIST-PCTS. > - */ > - > - if (info->params.data_rate) { > - char_time = info->timeout/(32 * 5); > - if (!char_time) > - char_time++; > - } else > - char_time = 1; > - > - if (timeout) > - char_time = min_t(unsigned long, char_time, timeout); > - > - if (info->params.mode == MGSL_MODE_HDLC) { > - while (info->tx_active) { > - msleep_interruptible(jiffies_to_msecs(char_time)); > - if (signal_pending(current)) > - break; > - if (timeout && time_after(jiffies, orig_jiffies + timeout)) > - break; > - } > - } else { > - while ((info->tx_count || info->tx_active) && > - info->tx_enabled) { > - msleep_interruptible(jiffies_to_msecs(char_time)); > - if (signal_pending(current)) > - break; > - if (timeout && time_after(jiffies, orig_jiffies + timeout)) > - break; > - } > - } > - > -exit: > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_wait_until_sent(%s) exit\n", > - __FILE__, __LINE__, info->device_name); > -} > - > -/* Called by tty_hangup() when a hangup is signaled. > - * This is the same as closing all open files for the port. > - */ > -static void mgslpc_hangup(struct tty_struct *tty) > -{ > - MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_hangup(%s)\n", > - __FILE__, __LINE__, info->device_name); > - > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_hangup")) > - return; > - > - mgslpc_flush_buffer(tty); > - shutdown(info, tty); > - tty_port_hangup(&info->port); > -} > - > -static bool carrier_raised(struct tty_port *port) > -{ > - MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port); > - unsigned long flags; > - > - spin_lock_irqsave(&info->lock, flags); > - get_signals(info); > - spin_unlock_irqrestore(&info->lock, flags); > - > - return info->serial_signals & SerialSignal_DCD; > -} > - > -static void dtr_rts(struct tty_port *port, bool active) > -{ > - MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port); > - unsigned long flags; > - > - spin_lock_irqsave(&info->lock, flags); > - if (active) > - info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; > - else > - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); > - set_signals(info); > - spin_unlock_irqrestore(&info->lock, flags); > -} > - > - > -static int mgslpc_open(struct tty_struct *tty, struct file * filp) > -{ > - MGSLPC_INFO *info; > - struct tty_port *port; > - int retval, line; > - unsigned long flags; > - > - /* verify range of specified line number */ > - line = tty->index; > - if (line >= mgslpc_device_count) { > - printk("%s(%d):mgslpc_open with invalid line #%d.\n", > - __FILE__, __LINE__, line); > - return -ENODEV; > - } > - > - /* find the info structure for the specified line */ > - info = mgslpc_device_list; > - while(info && info->line != line) > - info = info->next_device; > - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_open")) > - return -ENODEV; > - > - port = &info->port; > - tty->driver_data = info; > - tty_port_tty_set(port, tty); > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_open(%s), old ref count = %d\n", > - __FILE__, __LINE__, tty->driver->name, port->count); > - > - spin_lock_irqsave(&info->netlock, flags); > - if (info->netcount) { > - retval = -EBUSY; > - spin_unlock_irqrestore(&info->netlock, flags); > - goto cleanup; > - } > - spin_lock(&port->lock); > - port->count++; > - spin_unlock(&port->lock); > - spin_unlock_irqrestore(&info->netlock, flags); > - > - if (port->count == 1) { > - /* 1st open on this device, init hardware */ > - retval = startup(info, tty); > - if (retval < 0) > - goto cleanup; > - } > - > - retval = tty_port_block_til_ready(&info->port, tty, filp); > - if (retval) { > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):block_til_ready(%s) returned %d\n", > - __FILE__, __LINE__, info->device_name, retval); > - goto cleanup; > - } > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):mgslpc_open(%s) success\n", > - __FILE__, __LINE__, info->device_name); > - retval = 0; > - > -cleanup: > - return retval; > -} > - > -/* > - * /proc fs routines.... > - */ > - > -static inline void line_info(struct seq_file *m, MGSLPC_INFO *info) > -{ > - char stat_buf[30]; > - unsigned long flags; > - > - seq_printf(m, "%s:io:%04X irq:%d", > - info->device_name, info->io_base, info->irq_level); > - > - /* output current serial signal states */ > - spin_lock_irqsave(&info->lock, flags); > - get_signals(info); > - spin_unlock_irqrestore(&info->lock, flags); > - > - stat_buf[0] = 0; > - stat_buf[1] = 0; > - if (info->serial_signals & SerialSignal_RTS) > - strcat(stat_buf, "|RTS"); > - if (info->serial_signals & SerialSignal_CTS) > - strcat(stat_buf, "|CTS"); > - if (info->serial_signals & SerialSignal_DTR) > - strcat(stat_buf, "|DTR"); > - if (info->serial_signals & SerialSignal_DSR) > - strcat(stat_buf, "|DSR"); > - if (info->serial_signals & SerialSignal_DCD) > - strcat(stat_buf, "|CD"); > - if (info->serial_signals & SerialSignal_RI) > - strcat(stat_buf, "|RI"); > - > - if (info->params.mode == MGSL_MODE_HDLC) { > - seq_printf(m, " HDLC txok:%d rxok:%d", > - info->icount.txok, info->icount.rxok); > - if (info->icount.txunder) > - seq_printf(m, " txunder:%d", info->icount.txunder); > - if (info->icount.txabort) > - seq_printf(m, " txabort:%d", info->icount.txabort); > - if (info->icount.rxshort) > - seq_printf(m, " rxshort:%d", info->icount.rxshort); > - if (info->icount.rxlong) > - seq_printf(m, " rxlong:%d", info->icount.rxlong); > - if (info->icount.rxover) > - seq_printf(m, " rxover:%d", info->icount.rxover); > - if (info->icount.rxcrc) > - seq_printf(m, " rxcrc:%d", info->icount.rxcrc); > - } else { > - seq_printf(m, " ASYNC tx:%d rx:%d", > - info->icount.tx, info->icount.rx); > - if (info->icount.frame) > - seq_printf(m, " fe:%d", info->icount.frame); > - if (info->icount.parity) > - seq_printf(m, " pe:%d", info->icount.parity); > - if (info->icount.brk) > - seq_printf(m, " brk:%d", info->icount.brk); > - if (info->icount.overrun) > - seq_printf(m, " oe:%d", info->icount.overrun); > - } > - > - /* Append serial signal status to end */ > - seq_printf(m, " %s\n", stat_buf+1); > - > - seq_printf(m, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", > - info->tx_active,info->bh_requested,info->bh_running, > - info->pending_bh); > -} > - > -/* Called to print information about devices > - */ > -static int mgslpc_proc_show(struct seq_file *m, void *v) > -{ > - MGSLPC_INFO *info; > - > - seq_printf(m, "synclink driver:%s\n", driver_version); > - > - info = mgslpc_device_list; > - while (info) { > - line_info(m, info); > - info = info->next_device; > - } > - return 0; > -} > - > -static int rx_alloc_buffers(MGSLPC_INFO *info) > -{ > - /* each buffer has header and data */ > - info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size; > - > - /* calculate total allocation size for 8 buffers */ > - info->rx_buf_total_size = info->rx_buf_size * 8; > - > - /* limit total allocated memory */ > - if (info->rx_buf_total_size > 0x10000) > - info->rx_buf_total_size = 0x10000; > - > - /* calculate number of buffers */ > - info->rx_buf_count = info->rx_buf_total_size / info->rx_buf_size; > - > - info->rx_buf = kmalloc(info->rx_buf_total_size, GFP_KERNEL); > - if (info->rx_buf == NULL) > - return -ENOMEM; > - > - rx_reset_buffers(info); > - return 0; > -} > - > -static void rx_free_buffers(MGSLPC_INFO *info) > -{ > - kfree(info->rx_buf); > - info->rx_buf = NULL; > -} > - > -static int claim_resources(MGSLPC_INFO *info) > -{ > - if (rx_alloc_buffers(info) < 0) { > - printk("Can't allocate rx buffer %s\n", info->device_name); > - release_resources(info); > - return -ENODEV; > - } > - return 0; > -} > - > -static void release_resources(MGSLPC_INFO *info) > -{ > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("release_resources(%s)\n", info->device_name); > - rx_free_buffers(info); > -} > - > -/* Add the specified device instance data structure to the > - * global linked list of devices and increment the device count. > - * > - * Arguments: info pointer to device instance data > - */ > -static int mgslpc_add_device(MGSLPC_INFO *info) > -{ > - MGSLPC_INFO *current_dev = NULL; > - struct device *tty_dev; > - int ret; > - > - info->next_device = NULL; > - info->line = mgslpc_device_count; > - sprintf(info->device_name,"ttySLP%d",info->line); > - > - if (info->line < MAX_DEVICE_COUNT) { > - if (maxframe[info->line]) > - info->max_frame_size = maxframe[info->line]; > - } > - > - mgslpc_device_count++; > - > - if (!mgslpc_device_list) > - mgslpc_device_list = info; > - else { > - current_dev = mgslpc_device_list; > - while (current_dev->next_device) > - current_dev = current_dev->next_device; > - current_dev->next_device = info; > - } > - > - if (info->max_frame_size < 4096) > - info->max_frame_size = 4096; > - else if (info->max_frame_size > 65535) > - info->max_frame_size = 65535; > - > - printk("SyncLink PC Card %s:IO=%04X IRQ=%d\n", > - info->device_name, info->io_base, info->irq_level); > - > -#if SYNCLINK_GENERIC_HDLC > - ret = hdlcdev_init(info); > - if (ret != 0) > - goto failed; > -#endif > - > - tty_dev = tty_port_register_device(&info->port, serial_driver, info->line, > - &info->p_dev->dev); > - if (IS_ERR(tty_dev)) { > - ret = PTR_ERR(tty_dev); > -#if SYNCLINK_GENERIC_HDLC > - hdlcdev_exit(info); > -#endif > - goto failed; > - } > - > - return 0; > - > -failed: > - if (current_dev) > - current_dev->next_device = NULL; > - else > - mgslpc_device_list = NULL; > - mgslpc_device_count--; > - return ret; > -} > - > -static void mgslpc_remove_device(MGSLPC_INFO *remove_info) > -{ > - MGSLPC_INFO *info = mgslpc_device_list; > - MGSLPC_INFO *last = NULL; > - > - while(info) { > - if (info == remove_info) { > - if (last) > - last->next_device = info->next_device; > - else > - mgslpc_device_list = info->next_device; > - tty_unregister_device(serial_driver, info->line); > -#if SYNCLINK_GENERIC_HDLC > - hdlcdev_exit(info); > -#endif > - release_resources(info); > - tty_port_destroy(&info->port); > - kfree(info); > - mgslpc_device_count--; > - return; > - } > - last = info; > - info = info->next_device; > - } > -} > - > -static const struct pcmcia_device_id mgslpc_ids[] = { > - PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050), > - PCMCIA_DEVICE_NULL > -}; > -MODULE_DEVICE_TABLE(pcmcia, mgslpc_ids); > - > -static struct pcmcia_driver mgslpc_driver = { > - .owner = THIS_MODULE, > - .name = "synclink_cs", > - .probe = mgslpc_probe, > - .remove = mgslpc_detach, > - .id_table = mgslpc_ids, > - .suspend = mgslpc_suspend, > - .resume = mgslpc_resume, > -}; > - > -static const struct tty_operations mgslpc_ops = { > - .open = mgslpc_open, > - .close = mgslpc_close, > - .write = mgslpc_write, > - .put_char = mgslpc_put_char, > - .flush_chars = mgslpc_flush_chars, > - .write_room = mgslpc_write_room, > - .chars_in_buffer = mgslpc_chars_in_buffer, > - .flush_buffer = mgslpc_flush_buffer, > - .ioctl = mgslpc_ioctl, > - .throttle = mgslpc_throttle, > - .unthrottle = mgslpc_unthrottle, > - .send_xchar = mgslpc_send_xchar, > - .break_ctl = mgslpc_break, > - .wait_until_sent = mgslpc_wait_until_sent, > - .set_termios = mgslpc_set_termios, > - .stop = tx_pause, > - .start = tx_release, > - .hangup = mgslpc_hangup, > - .tiocmget = tiocmget, > - .tiocmset = tiocmset, > - .get_icount = mgslpc_get_icount, > - .proc_show = mgslpc_proc_show, > -}; > - > -static int __init synclink_cs_init(void) > -{ > - int rc; > - > - if (break_on_load) { > - mgslpc_get_text_ptr(); > - BREAKPOINT(); > - } > - > - serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT, > - TTY_DRIVER_REAL_RAW | > - TTY_DRIVER_DYNAMIC_DEV); > - if (IS_ERR(serial_driver)) { > - rc = PTR_ERR(serial_driver); > - goto err; > - } > - > - /* Initialize the tty_driver structure */ > - serial_driver->driver_name = "synclink_cs"; > - serial_driver->name = "ttySLP"; > - serial_driver->major = ttymajor; > - serial_driver->minor_start = 64; > - serial_driver->type = TTY_DRIVER_TYPE_SERIAL; > - serial_driver->subtype = SERIAL_TYPE_NORMAL; > - serial_driver->init_termios = tty_std_termios; > - serial_driver->init_termios.c_cflag = > - B9600 | CS8 | CREAD | HUPCL | CLOCAL; > - tty_set_operations(serial_driver, &mgslpc_ops); > - > - rc = tty_register_driver(serial_driver); > - if (rc < 0) { > - printk(KERN_ERR "%s(%d):Couldn't register serial driver\n", > - __FILE__, __LINE__); > - goto err_put_tty; > - } > - > - rc = pcmcia_register_driver(&mgslpc_driver); > - if (rc < 0) > - goto err_unreg_tty; > - > - printk(KERN_INFO "%s %s, tty major#%d\n", driver_name, driver_version, > - serial_driver->major); > - > - return 0; > -err_unreg_tty: > - tty_unregister_driver(serial_driver); > -err_put_tty: > - tty_driver_kref_put(serial_driver); > -err: > - return rc; > -} > - > -static void __exit synclink_cs_exit(void) > -{ > - pcmcia_unregister_driver(&mgslpc_driver); > - tty_unregister_driver(serial_driver); > - tty_driver_kref_put(serial_driver); > -} > - > -module_init(synclink_cs_init); > -module_exit(synclink_cs_exit); > - > -static void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate) > -{ > - unsigned int M, N; > - unsigned char val; > - > - /* note:standard BRG mode is broken in V3.2 chip > - * so enhanced mode is always used > - */ > - > - if (rate) { > - N = 3686400 / rate; > - if (!N) > - N = 1; > - N >>= 1; > - for (M = 1; N > 64 && M < 16; M++) > - N >>= 1; > - N--; > - > - /* BGR[5..0] = N > - * BGR[9..6] = M > - * BGR[7..0] contained in BGR register > - * BGR[9..8] contained in CCR2[7..6] > - * divisor = (N+1)*2^M > - * > - * Note: M *must* not be zero (causes asymetric duty cycle) > - */ > - write_reg(info, (unsigned char) (channel + BGR), > - (unsigned char) ((M << 6) + N)); > - val = read_reg(info, (unsigned char) (channel + CCR2)) & 0x3f; > - val |= ((M << 4) & 0xc0); > - write_reg(info, (unsigned char) (channel + CCR2), val); > - } > -} > - > -/* Enabled the AUX clock output at the specified frequency. > - */ > -static void enable_auxclk(MGSLPC_INFO *info) > -{ > - unsigned char val; > - > - /* MODE > - * > - * 07..06 MDS[1..0] 10 = transparent HDLC mode > - * 05 ADM Address Mode, 0 = no addr recognition > - * 04 TMD Timer Mode, 0 = external > - * 03 RAC Receiver Active, 0 = inactive > - * 02 RTS 0=RTS active during xmit, 1=RTS always active > - * 01 TRS Timer Resolution, 1=512 > - * 00 TLP Test Loop, 0 = no loop > - * > - * 1000 0010 > - */ > - val = 0x82; > - > - /* channel B RTS is used to enable AUXCLK driver on SP505 */ > - if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed) > - val |= BIT2; > - write_reg(info, CHB + MODE, val); > - > - /* CCR0 > - * > - * 07 PU Power Up, 1=active, 0=power down > - * 06 MCE Master Clock Enable, 1=enabled > - * 05 Reserved, 0 > - * 04..02 SC[2..0] Encoding > - * 01..00 SM[1..0] Serial Mode, 00=HDLC > - * > - * 11000000 > - */ > - write_reg(info, CHB + CCR0, 0xc0); > - > - /* CCR1 > - * > - * 07 SFLG Shared Flag, 0 = disable shared flags > - * 06 GALP Go Active On Loop, 0 = not used > - * 05 GLP Go On Loop, 0 = not used > - * 04 ODS Output Driver Select, 1=TxD is push-pull output > - * 03 ITF Interframe Time Fill, 0=mark, 1=flag > - * 02..00 CM[2..0] Clock Mode > - * > - * 0001 0111 > - */ > - write_reg(info, CHB + CCR1, 0x17); > - > - /* CCR2 (Channel B) > - * > - * 07..06 BGR[9..8] Baud rate bits 9..8 > - * 05 BDF Baud rate divisor factor, 0=1, 1=BGR value > - * 04 SSEL Clock source select, 1=submode b > - * 03 TOE 0=TxCLK is input, 1=TxCLK is output > - * 02 RWX Read/Write Exchange 0=disabled > - * 01 C32, CRC select, 0=CRC-16, 1=CRC-32 > - * 00 DIV, data inversion 0=disabled, 1=enabled > - * > - * 0011 1000 > - */ > - if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed) > - write_reg(info, CHB + CCR2, 0x38); > - else > - write_reg(info, CHB + CCR2, 0x30); > - > - /* CCR4 > - * > - * 07 MCK4 Master Clock Divide by 4, 1=enabled > - * 06 EBRG Enhanced Baud Rate Generator Mode, 1=enabled > - * 05 TST1 Test Pin, 0=normal operation > - * 04 ICD Ivert Carrier Detect, 1=enabled (active low) > - * 03..02 Reserved, must be 0 > - * 01..00 RFT[1..0] RxFIFO Threshold 00=32 bytes > - * > - * 0101 0000 > - */ > - write_reg(info, CHB + CCR4, 0x50); > - > - /* if auxclk not enabled, set internal BRG so > - * CTS transitions can be detected (requires TxC) > - */ > - if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed) > - mgslpc_set_rate(info, CHB, info->params.clock_speed); > - else > - mgslpc_set_rate(info, CHB, 921600); > -} > - > -static void loopback_enable(MGSLPC_INFO *info) > -{ > - unsigned char val; > - > - /* CCR1:02..00 CM[2..0] Clock Mode = 111 (clock mode 7) */ > - val = read_reg(info, CHA + CCR1) | (BIT2 | BIT1 | BIT0); > - write_reg(info, CHA + CCR1, val); > - > - /* CCR2:04 SSEL Clock source select, 1=submode b */ > - val = read_reg(info, CHA + CCR2) | (BIT4 | BIT5); > - write_reg(info, CHA + CCR2, val); > - > - /* set LinkSpeed if available, otherwise default to 2Mbps */ > - if (info->params.clock_speed) > - mgslpc_set_rate(info, CHA, info->params.clock_speed); > - else > - mgslpc_set_rate(info, CHA, 1843200); > - > - /* MODE:00 TLP Test Loop, 1=loopback enabled */ > - val = read_reg(info, CHA + MODE) | BIT0; > - write_reg(info, CHA + MODE, val); > -} > - > -static void hdlc_mode(MGSLPC_INFO *info) > -{ > - unsigned char val; > - unsigned char clkmode, clksubmode; > - > - /* disable all interrupts */ > - irq_disable(info, CHA, 0xffff); > - irq_disable(info, CHB, 0xffff); > - port_irq_disable(info, 0xff); > - > - /* assume clock mode 0a, rcv=RxC xmt=TxC */ > - clkmode = clksubmode = 0; > - if (info->params.flags & HDLC_FLAG_RXC_DPLL > - && info->params.flags & HDLC_FLAG_TXC_DPLL) { > - /* clock mode 7a, rcv = DPLL, xmt = DPLL */ > - clkmode = 7; > - } else if (info->params.flags & HDLC_FLAG_RXC_BRG > - && info->params.flags & HDLC_FLAG_TXC_BRG) { > - /* clock mode 7b, rcv = BRG, xmt = BRG */ > - clkmode = 7; > - clksubmode = 1; > - } else if (info->params.flags & HDLC_FLAG_RXC_DPLL) { > - if (info->params.flags & HDLC_FLAG_TXC_BRG) { > - /* clock mode 6b, rcv = DPLL, xmt = BRG/16 */ > - clkmode = 6; > - clksubmode = 1; > - } else { > - /* clock mode 6a, rcv = DPLL, xmt = TxC */ > - clkmode = 6; > - } > - } else if (info->params.flags & HDLC_FLAG_TXC_BRG) { > - /* clock mode 0b, rcv = RxC, xmt = BRG */ > - clksubmode = 1; > - } > - > - /* MODE > - * > - * 07..06 MDS[1..0] 10 = transparent HDLC mode > - * 05 ADM Address Mode, 0 = no addr recognition > - * 04 TMD Timer Mode, 0 = external > - * 03 RAC Receiver Active, 0 = inactive > - * 02 RTS 0=RTS active during xmit, 1=RTS always active > - * 01 TRS Timer Resolution, 1=512 > - * 00 TLP Test Loop, 0 = no loop > - * > - * 1000 0010 > - */ > - val = 0x82; > - if (info->params.loopback) > - val |= BIT0; > - > - /* preserve RTS state */ > - if (info->serial_signals & SerialSignal_RTS) > - val |= BIT2; > - write_reg(info, CHA + MODE, val); > - > - /* CCR0 > - * > - * 07 PU Power Up, 1=active, 0=power down > - * 06 MCE Master Clock Enable, 1=enabled > - * 05 Reserved, 0 > - * 04..02 SC[2..0] Encoding > - * 01..00 SM[1..0] Serial Mode, 00=HDLC > - * > - * 11000000 > - */ > - val = 0xc0; > - switch (info->params.encoding) > - { > - case HDLC_ENCODING_NRZI: > - val |= BIT3; > - break; > - case HDLC_ENCODING_BIPHASE_SPACE: > - val |= BIT4; > - break; // FM0 > - case HDLC_ENCODING_BIPHASE_MARK: > - val |= BIT4 | BIT2; > - break; // FM1 > - case HDLC_ENCODING_BIPHASE_LEVEL: > - val |= BIT4 | BIT3; > - break; // Manchester > - } > - write_reg(info, CHA + CCR0, val); > - > - /* CCR1 > - * > - * 07 SFLG Shared Flag, 0 = disable shared flags > - * 06 GALP Go Active On Loop, 0 = not used > - * 05 GLP Go On Loop, 0 = not used > - * 04 ODS Output Driver Select, 1=TxD is push-pull output > - * 03 ITF Interframe Time Fill, 0=mark, 1=flag > - * 02..00 CM[2..0] Clock Mode > - * > - * 0001 0000 > - */ > - val = 0x10 + clkmode; > - write_reg(info, CHA + CCR1, val); > - > - /* CCR2 > - * > - * 07..06 BGR[9..8] Baud rate bits 9..8 > - * 05 BDF Baud rate divisor factor, 0=1, 1=BGR value > - * 04 SSEL Clock source select, 1=submode b > - * 03 TOE 0=TxCLK is input, 0=TxCLK is input > - * 02 RWX Read/Write Exchange 0=disabled > - * 01 C32, CRC select, 0=CRC-16, 1=CRC-32 > - * 00 DIV, data inversion 0=disabled, 1=enabled > - * > - * 0000 0000 > - */ > - val = 0x00; > - if (clkmode == 2 || clkmode == 3 || clkmode == 6 > - || clkmode == 7 || (clkmode == 0 && clksubmode == 1)) > - val |= BIT5; > - if (clksubmode) > - val |= BIT4; > - if (info->params.crc_type == HDLC_CRC_32_CCITT) > - val |= BIT1; > - if (info->params.encoding == HDLC_ENCODING_NRZB) > - val |= BIT0; > - write_reg(info, CHA + CCR2, val); > - > - /* CCR3 > - * > - * 07..06 PRE[1..0] Preamble count 00=1, 01=2, 10=4, 11=8 > - * 05 EPT Enable preamble transmission, 1=enabled > - * 04 RADD Receive address pushed to FIFO, 0=disabled > - * 03 CRL CRC Reset Level, 0=FFFF > - * 02 RCRC Rx CRC 0=On 1=Off > - * 01 TCRC Tx CRC 0=On 1=Off > - * 00 PSD DPLL Phase Shift Disable > - * > - * 0000 0000 > - */ > - val = 0x00; > - if (info->params.crc_type == HDLC_CRC_NONE) > - val |= BIT2 | BIT1; > - if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE) > - val |= BIT5; > - switch (info->params.preamble_length) > - { > - case HDLC_PREAMBLE_LENGTH_16BITS: > - val |= BIT6; > - break; > - case HDLC_PREAMBLE_LENGTH_32BITS: > - val |= BIT6; > - break; > - case HDLC_PREAMBLE_LENGTH_64BITS: > - val |= BIT7 | BIT6; > - break; > - } > - write_reg(info, CHA + CCR3, val); > - > - /* PRE - Preamble pattern */ > - val = 0; > - switch (info->params.preamble) > - { > - case HDLC_PREAMBLE_PATTERN_FLAGS: val = 0x7e; break; > - case HDLC_PREAMBLE_PATTERN_10: val = 0xaa; break; > - case HDLC_PREAMBLE_PATTERN_01: val = 0x55; break; > - case HDLC_PREAMBLE_PATTERN_ONES: val = 0xff; break; > - } > - write_reg(info, CHA + PRE, val); > - > - /* CCR4 > - * > - * 07 MCK4 Master Clock Divide by 4, 1=enabled > - * 06 EBRG Enhanced Baud Rate Generator Mode, 1=enabled > - * 05 TST1 Test Pin, 0=normal operation > - * 04 ICD Ivert Carrier Detect, 1=enabled (active low) > - * 03..02 Reserved, must be 0 > - * 01..00 RFT[1..0] RxFIFO Threshold 00=32 bytes > - * > - * 0101 0000 > - */ > - val = 0x50; > - write_reg(info, CHA + CCR4, val); > - if (info->params.flags & HDLC_FLAG_RXC_DPLL) > - mgslpc_set_rate(info, CHA, info->params.clock_speed * 16); > - else > - mgslpc_set_rate(info, CHA, info->params.clock_speed); > - > - /* RLCR Receive length check register > - * > - * 7 1=enable receive length check > - * 6..0 Max frame length = (RL + 1) * 32 > - */ > - write_reg(info, CHA + RLCR, 0); > - > - /* XBCH Transmit Byte Count High > - * > - * 07 DMA mode, 0 = interrupt driven > - * 06 NRM, 0=ABM (ignored) > - * 05 CAS Carrier Auto Start > - * 04 XC Transmit Continuously (ignored) > - * 03..00 XBC[10..8] Transmit byte count bits 10..8 > - * > - * 0000 0000 > - */ > - val = 0x00; > - if (info->params.flags & HDLC_FLAG_AUTO_DCD) > - val |= BIT5; > - write_reg(info, CHA + XBCH, val); > - enable_auxclk(info); > - if (info->params.loopback || info->testing_irq) > - loopback_enable(info); > - if (info->params.flags & HDLC_FLAG_AUTO_CTS) > - { > - irq_enable(info, CHB, IRQ_CTS); > - /* PVR[3] 1=AUTO CTS active */ > - set_reg_bits(info, CHA + PVR, BIT3); > - } else > - clear_reg_bits(info, CHA + PVR, BIT3); > - > - irq_enable(info, CHA, > - IRQ_RXEOM | IRQ_RXFIFO | IRQ_ALLSENT | > - IRQ_UNDERRUN | IRQ_TXFIFO); > - issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET); > - wait_command_complete(info, CHA); > - read_reg16(info, CHA + ISR); /* clear pending IRQs */ > - > - /* Master clock mode enabled above to allow reset commands > - * to complete even if no data clocks are present. > - * > - * Disable master clock mode for normal communications because > - * V3.2 of the ESCC2 has a bug that prevents the transmit all sent > - * IRQ when in master clock mode. > - * > - * Leave master clock mode enabled for IRQ test because the > - * timer IRQ used by the test can only happen in master clock mode. > - */ > - if (!info->testing_irq) > - clear_reg_bits(info, CHA + CCR0, BIT6); > - > - tx_set_idle(info); > - > - tx_stop(info); > - rx_stop(info); > -} > - > -static void rx_stop(MGSLPC_INFO *info) > -{ > - if (debug_level >= DEBUG_LEVEL_ISR) > - printk("%s(%d):rx_stop(%s)\n", > - __FILE__, __LINE__, info->device_name); > - > - /* MODE:03 RAC Receiver Active, 0=inactive */ > - clear_reg_bits(info, CHA + MODE, BIT3); > - > - info->rx_enabled = false; > - info->rx_overflow = false; > -} > - > -static void rx_start(MGSLPC_INFO *info) > -{ > - if (debug_level >= DEBUG_LEVEL_ISR) > - printk("%s(%d):rx_start(%s)\n", > - __FILE__, __LINE__, info->device_name); > - > - rx_reset_buffers(info); > - info->rx_enabled = false; > - info->rx_overflow = false; > - > - /* MODE:03 RAC Receiver Active, 1=active */ > - set_reg_bits(info, CHA + MODE, BIT3); > - > - info->rx_enabled = true; > -} > - > -static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty) > -{ > - if (debug_level >= DEBUG_LEVEL_ISR) > - printk("%s(%d):tx_start(%s)\n", > - __FILE__, __LINE__, info->device_name); > - > - if (info->tx_count) { > - /* If auto RTS enabled and RTS is inactive, then assert */ > - /* RTS and set a flag indicating that the driver should */ > - /* negate RTS when the transmission completes. */ > - info->drop_rts_on_tx_done = false; > - > - if (info->params.flags & HDLC_FLAG_AUTO_RTS) { > - get_signals(info); > - if (!(info->serial_signals & SerialSignal_RTS)) { > - info->serial_signals |= SerialSignal_RTS; > - set_signals(info); > - info->drop_rts_on_tx_done = true; > - } > - } > - > - if (info->params.mode == MGSL_MODE_ASYNC) { > - if (!info->tx_active) { > - info->tx_active = true; > - tx_ready(info, tty); > - } > - } else { > - info->tx_active = true; > - tx_ready(info, tty); > - mod_timer(&info->tx_timer, jiffies + > - msecs_to_jiffies(5000)); > - } > - } > - > - if (!info->tx_enabled) > - info->tx_enabled = true; > -} > - > -static void tx_stop(MGSLPC_INFO *info) > -{ > - if (debug_level >= DEBUG_LEVEL_ISR) > - printk("%s(%d):tx_stop(%s)\n", > - __FILE__, __LINE__, info->device_name); > - > - del_timer(&info->tx_timer); > - > - info->tx_enabled = false; > - info->tx_active = false; > -} > - > -/* Reset the adapter to a known state and prepare it for further use. > - */ > -static void reset_device(MGSLPC_INFO *info) > -{ > - /* power up both channels (set BIT7) */ > - write_reg(info, CHA + CCR0, 0x80); > - write_reg(info, CHB + CCR0, 0x80); > - write_reg(info, CHA + MODE, 0); > - write_reg(info, CHB + MODE, 0); > - > - /* disable all interrupts */ > - irq_disable(info, CHA, 0xffff); > - irq_disable(info, CHB, 0xffff); > - port_irq_disable(info, 0xff); > - > - /* PCR Port Configuration Register > - * > - * 07..04 DEC[3..0] Serial I/F select outputs > - * 03 output, 1=AUTO CTS control enabled > - * 02 RI Ring Indicator input 0=active > - * 01 DSR input 0=active > - * 00 DTR output 0=active > - * > - * 0000 0110 > - */ > - write_reg(info, PCR, 0x06); > - > - /* PVR Port Value Register > - * > - * 07..04 DEC[3..0] Serial I/F select (0000=disabled) > - * 03 AUTO CTS output 1=enabled > - * 02 RI Ring Indicator input > - * 01 DSR input > - * 00 DTR output (1=inactive) > - * > - * 0000 0001 > - */ > -// write_reg(info, PVR, PVR_DTR); > - > - /* IPC Interrupt Port Configuration > - * > - * 07 VIS 1=Masked interrupts visible > - * 06..05 Reserved, 0 > - * 04..03 SLA Slave address, 00 ignored > - * 02 CASM Cascading Mode, 1=daisy chain > - * 01..00 IC[1..0] Interrupt Config, 01=push-pull output, active low > - * > - * 0000 0101 > - */ > - write_reg(info, IPC, 0x05); > -} > - > -static void async_mode(MGSLPC_INFO *info) > -{ > - unsigned char val; > - > - /* disable all interrupts */ > - irq_disable(info, CHA, 0xffff); > - irq_disable(info, CHB, 0xffff); > - port_irq_disable(info, 0xff); > - > - /* MODE > - * > - * 07 Reserved, 0 > - * 06 FRTS RTS State, 0=active > - * 05 FCTS Flow Control on CTS > - * 04 FLON Flow Control Enable > - * 03 RAC Receiver Active, 0 = inactive > - * 02 RTS 0=Auto RTS, 1=manual RTS > - * 01 TRS Timer Resolution, 1=512 > - * 00 TLP Test Loop, 0 = no loop > - * > - * 0000 0110 > - */ > - val = 0x06; > - if (info->params.loopback) > - val |= BIT0; > - > - /* preserve RTS state */ > - if (!(info->serial_signals & SerialSignal_RTS)) > - val |= BIT6; > - write_reg(info, CHA + MODE, val); > - > - /* CCR0 > - * > - * 07 PU Power Up, 1=active, 0=power down > - * 06 MCE Master Clock Enable, 1=enabled > - * 05 Reserved, 0 > - * 04..02 SC[2..0] Encoding, 000=NRZ > - * 01..00 SM[1..0] Serial Mode, 11=Async > - * > - * 1000 0011 > - */ > - write_reg(info, CHA + CCR0, 0x83); > - > - /* CCR1 > - * > - * 07..05 Reserved, 0 > - * 04 ODS Output Driver Select, 1=TxD is push-pull output > - * 03 BCR Bit Clock Rate, 1=16x > - * 02..00 CM[2..0] Clock Mode, 111=BRG > - * > - * 0001 1111 > - */ > - write_reg(info, CHA + CCR1, 0x1f); > - > - /* CCR2 (channel A) > - * > - * 07..06 BGR[9..8] Baud rate bits 9..8 > - * 05 BDF Baud rate divisor factor, 0=1, 1=BGR value > - * 04 SSEL Clock source select, 1=submode b > - * 03 TOE 0=TxCLK is input, 0=TxCLK is input > - * 02 RWX Read/Write Exchange 0=disabled > - * 01 Reserved, 0 > - * 00 DIV, data inversion 0=disabled, 1=enabled > - * > - * 0001 0000 > - */ > - write_reg(info, CHA + CCR2, 0x10); > - > - /* CCR3 > - * > - * 07..01 Reserved, 0 > - * 00 PSD DPLL Phase Shift Disable > - * > - * 0000 0000 > - */ > - write_reg(info, CHA + CCR3, 0); > - > - /* CCR4 > - * > - * 07 MCK4 Master Clock Divide by 4, 1=enabled > - * 06 EBRG Enhanced Baud Rate Generator Mode, 1=enabled > - * 05 TST1 Test Pin, 0=normal operation > - * 04 ICD Ivert Carrier Detect, 1=enabled (active low) > - * 03..00 Reserved, must be 0 > - * > - * 0101 0000 > - */ > - write_reg(info, CHA + CCR4, 0x50); > - mgslpc_set_rate(info, CHA, info->params.data_rate * 16); > - > - /* DAFO Data Format > - * > - * 07 Reserved, 0 > - * 06 XBRK transmit break, 0=normal operation > - * 05 Stop bits (0=1, 1=2) > - * 04..03 PAR[1..0] Parity (01=odd, 10=even) > - * 02 PAREN Parity Enable > - * 01..00 CHL[1..0] Character Length (00=8, 01=7) > - * > - */ > - val = 0x00; > - if (info->params.data_bits != 8) > - val |= BIT0; /* 7 bits */ > - if (info->params.stop_bits != 1) > - val |= BIT5; > - if (info->params.parity != ASYNC_PARITY_NONE) > - { > - val |= BIT2; /* Parity enable */ > - if (info->params.parity == ASYNC_PARITY_ODD) > - val |= BIT3; > - else > - val |= BIT4; > - } > - write_reg(info, CHA + DAFO, val); > - > - /* RFC Rx FIFO Control > - * > - * 07 Reserved, 0 > - * 06 DPS, 1=parity bit not stored in data byte > - * 05 DXS, 0=all data stored in FIFO (including XON/XOFF) > - * 04 RFDF Rx FIFO Data Format, 1=status byte stored in FIFO > - * 03..02 RFTH[1..0], rx threshold, 11=16 status + 16 data byte > - * 01 Reserved, 0 > - * 00 TCDE Terminate Char Detect Enable, 0=disabled > - * > - * 0101 1100 > - */ > - write_reg(info, CHA + RFC, 0x5c); > - > - /* RLCR Receive length check register > - * > - * Max frame length = (RL + 1) * 32 > - */ > - write_reg(info, CHA + RLCR, 0); > - > - /* XBCH Transmit Byte Count High > - * > - * 07 DMA mode, 0 = interrupt driven > - * 06 NRM, 0=ABM (ignored) > - * 05 CAS Carrier Auto Start > - * 04 XC Transmit Continuously (ignored) > - * 03..00 XBC[10..8] Transmit byte count bits 10..8 > - * > - * 0000 0000 > - */ > - val = 0x00; > - if (info->params.flags & HDLC_FLAG_AUTO_DCD) > - val |= BIT5; > - write_reg(info, CHA + XBCH, val); > - if (info->params.flags & HDLC_FLAG_AUTO_CTS) > - irq_enable(info, CHA, IRQ_CTS); > - > - /* MODE:03 RAC Receiver Active, 1=active */ > - set_reg_bits(info, CHA + MODE, BIT3); > - enable_auxclk(info); > - if (info->params.flags & HDLC_FLAG_AUTO_CTS) { > - irq_enable(info, CHB, IRQ_CTS); > - /* PVR[3] 1=AUTO CTS active */ > - set_reg_bits(info, CHA + PVR, BIT3); > - } else > - clear_reg_bits(info, CHA + PVR, BIT3); > - irq_enable(info, CHA, > - IRQ_RXEOM | IRQ_RXFIFO | IRQ_BREAK_ON | IRQ_RXTIME | > - IRQ_ALLSENT | IRQ_TXFIFO); > - issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET); > - wait_command_complete(info, CHA); > - read_reg16(info, CHA + ISR); /* clear pending IRQs */ > -} > - > -/* Set the HDLC idle mode for the transmitter. > - */ > -static void tx_set_idle(MGSLPC_INFO *info) > -{ > - /* Note: ESCC2 only supports flags and one idle modes */ > - if (info->idle_mode == HDLC_TXIDLE_FLAGS) > - set_reg_bits(info, CHA + CCR1, BIT3); > - else > - clear_reg_bits(info, CHA + CCR1, BIT3); > -} > - > -/* get state of the V24 status (input) signals. > - */ > -static void get_signals(MGSLPC_INFO *info) > -{ > - unsigned char status = 0; > - > - /* preserve RTS and DTR */ > - info->serial_signals &= SerialSignal_RTS | SerialSignal_DTR; > - > - if (read_reg(info, CHB + VSTR) & BIT7) > - info->serial_signals |= SerialSignal_DCD; > - if (read_reg(info, CHB + STAR) & BIT1) > - info->serial_signals |= SerialSignal_CTS; > - > - status = read_reg(info, CHA + PVR); > - if (!(status & PVR_RI)) > - info->serial_signals |= SerialSignal_RI; > - if (!(status & PVR_DSR)) > - info->serial_signals |= SerialSignal_DSR; > -} > - > -/* Set the state of RTS and DTR based on contents of > - * serial_signals member of device extension. > - */ > -static void set_signals(MGSLPC_INFO *info) > -{ > - unsigned char val; > - > - val = read_reg(info, CHA + MODE); > - if (info->params.mode == MGSL_MODE_ASYNC) { > - if (info->serial_signals & SerialSignal_RTS) > - val &= ~BIT6; > - else > - val |= BIT6; > - } else { > - if (info->serial_signals & SerialSignal_RTS) > - val |= BIT2; > - else > - val &= ~BIT2; > - } > - write_reg(info, CHA + MODE, val); > - > - if (info->serial_signals & SerialSignal_DTR) > - clear_reg_bits(info, CHA + PVR, PVR_DTR); > - else > - set_reg_bits(info, CHA + PVR, PVR_DTR); > -} > - > -static void rx_reset_buffers(MGSLPC_INFO *info) > -{ > - RXBUF *buf; > - int i; > - > - info->rx_put = 0; > - info->rx_get = 0; > - info->rx_frame_count = 0; > - for (i=0 ; i < info->rx_buf_count ; i++) { > - buf = (RXBUF*)(info->rx_buf + (i * info->rx_buf_size)); > - buf->status = buf->count = 0; > - } > -} > - > -/* Attempt to return a received HDLC frame > - * Only frames received without errors are returned. > - * > - * Returns true if frame returned, otherwise false > - */ > -static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty) > -{ > - unsigned short status; > - RXBUF *buf; > - unsigned int framesize = 0; > - unsigned long flags; > - bool return_frame = false; > - > - if (info->rx_frame_count == 0) > - return false; > - > - buf = (RXBUF*)(info->rx_buf + (info->rx_get * info->rx_buf_size)); > - > - status = buf->status; > - > - /* 07 VFR 1=valid frame > - * 06 RDO 1=data overrun > - * 05 CRC 1=OK, 0=error > - * 04 RAB 1=frame aborted > - */ > - if ((status & 0xf0) != 0xA0) { > - if (!(status & BIT7) || (status & BIT4)) > - info->icount.rxabort++; > - else if (status & BIT6) > - info->icount.rxover++; > - else if (!(status & BIT5)) { > - info->icount.rxcrc++; > - if (info->params.crc_type & HDLC_CRC_RETURN_EX) > - return_frame = true; > - } > - framesize = 0; > -#if SYNCLINK_GENERIC_HDLC > - { > - info->netdev->stats.rx_errors++; > - info->netdev->stats.rx_frame_errors++; > - } > -#endif > - } else > - return_frame = true; > - > - if (return_frame) > - framesize = buf->count; > - > - if (debug_level >= DEBUG_LEVEL_BH) > - printk("%s(%d):rx_get_frame(%s) status=%04X size=%d\n", > - __FILE__, __LINE__, info->device_name, status, framesize); > - > - if (debug_level >= DEBUG_LEVEL_DATA) > - trace_block(info, buf->data, framesize, 0); > - > - if (framesize) { > - if ((info->params.crc_type & HDLC_CRC_RETURN_EX && > - framesize+1 > info->max_frame_size) || > - framesize > info->max_frame_size) > - info->icount.rxlong++; > - else { > - if (status & BIT5) > - info->icount.rxok++; > - > - if (info->params.crc_type & HDLC_CRC_RETURN_EX) { > - *(buf->data + framesize) = status & BIT5 ? RX_OK:RX_CRC_ERROR; > - ++framesize; > - } > - > -#if SYNCLINK_GENERIC_HDLC > - if (info->netcount) > - hdlcdev_rx(info, buf->data, framesize); > - else > -#endif > - ldisc_receive_buf(tty, buf->data, NULL, > - framesize); > - } > - } > - > - spin_lock_irqsave(&info->lock, flags); > - buf->status = buf->count = 0; > - info->rx_frame_count--; > - info->rx_get++; > - if (info->rx_get >= info->rx_buf_count) > - info->rx_get = 0; > - spin_unlock_irqrestore(&info->lock, flags); > - > - return true; > -} > - > -static bool register_test(MGSLPC_INFO *info) > -{ > - static unsigned char patterns[] = > - { 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f }; > - static unsigned int count = ARRAY_SIZE(patterns); > - unsigned int i; > - bool rc = true; > - unsigned long flags; > - > - spin_lock_irqsave(&info->lock, flags); > - reset_device(info); > - > - for (i = 0; i < count; i++) { > - write_reg(info, XAD1, patterns[i]); > - write_reg(info, XAD2, patterns[(i + 1) % count]); > - if ((read_reg(info, XAD1) != patterns[i]) || > - (read_reg(info, XAD2) != patterns[(i + 1) % count])) { > - rc = false; > - break; > - } > - } > - > - spin_unlock_irqrestore(&info->lock, flags); > - return rc; > -} > - > -static bool irq_test(MGSLPC_INFO *info) > -{ > - unsigned long end_time; > - unsigned long flags; > - > - spin_lock_irqsave(&info->lock, flags); > - reset_device(info); > - > - info->testing_irq = true; > - hdlc_mode(info); > - > - info->irq_occurred = false; > - > - /* init hdlc mode */ > - > - irq_enable(info, CHA, IRQ_TIMER); > - write_reg(info, CHA + TIMR, 0); /* 512 cycles */ > - issue_command(info, CHA, CMD_START_TIMER); > - > - spin_unlock_irqrestore(&info->lock, flags); > - > - end_time=100; > - while(end_time-- && !info->irq_occurred) { > - msleep_interruptible(10); > - } > - > - info->testing_irq = false; > - > - spin_lock_irqsave(&info->lock, flags); > - reset_device(info); > - spin_unlock_irqrestore(&info->lock, flags); > - > - return info->irq_occurred; > -} > - > -static int adapter_test(MGSLPC_INFO *info) > -{ > - if (!register_test(info)) { > - info->init_error = DiagStatus_AddressFailure; > - printk("%s(%d):Register test failure for device %s Addr=%04X\n", > - __FILE__, __LINE__, info->device_name, (unsigned short)(info->io_base)); > - return -ENODEV; > - } > - > - if (!irq_test(info)) { > - info->init_error = DiagStatus_IrqFailure; > - printk("%s(%d):Interrupt test failure for device %s IRQ=%d\n", > - __FILE__, __LINE__, info->device_name, (unsigned short)(info->irq_level)); > - return -ENODEV; > - } > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):device %s passed diagnostics\n", > - __FILE__, __LINE__, info->device_name); > - return 0; > -} > - > -static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit) > -{ > - int i; > - int linecount; > - if (xmit) > - printk("%s tx data:\n", info->device_name); > - else > - printk("%s rx data:\n", info->device_name); > - > - while(count) { > - if (count > 16) > - linecount = 16; > - else > - linecount = count; > - > - for(i=0;i - printk("%02X ", (unsigned char)data[i]); > - for(;i<17;i++) > - printk(" "); > - for(i=0;i - if (data[i]>=040 && data[i]<=0176) > - printk("%c", data[i]); > - else > - printk("."); > - } > - printk("\n"); > - > - data += linecount; > - count -= linecount; > - } > -} > - > -/* HDLC frame time out > - * update stats and do tx completion processing > - */ > -static void tx_timeout(struct timer_list *t) > -{ > - MGSLPC_INFO *info = from_timer(info, t, tx_timer); > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s(%d):tx_timeout(%s)\n", > - __FILE__, __LINE__, info->device_name); > - if (info->tx_active && > - info->params.mode == MGSL_MODE_HDLC) { > - info->icount.txtimeout++; > - } > - spin_lock_irqsave(&info->lock, flags); > - info->tx_active = false; > - info->tx_count = info->tx_put = info->tx_get = 0; > - > - spin_unlock_irqrestore(&info->lock, flags); > - > -#if SYNCLINK_GENERIC_HDLC > - if (info->netcount) > - hdlcdev_tx_done(info); > - else > -#endif > - { > - struct tty_struct *tty = tty_port_tty_get(&info->port); > - bh_transmit(info, tty); > - tty_kref_put(tty); > - } > -} > - > -#if SYNCLINK_GENERIC_HDLC > - > -/* > - * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) > - * set encoding and frame check sequence (FCS) options > - * > - * dev pointer to network device structure > - * encoding serial encoding setting > - * parity FCS setting > - * > - * returns 0 if success, otherwise error code > - */ > -static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, > - unsigned short parity) > -{ > - MGSLPC_INFO *info = dev_to_port(dev); > - struct tty_struct *tty; > - unsigned char new_encoding; > - unsigned short new_crctype; > - > - /* return error if TTY interface open */ > - if (info->port.count) > - return -EBUSY; > - > - switch (encoding) > - { > - case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; > - case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; > - case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; > - case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; > - case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; > - default: return -EINVAL; > - } > - > - switch (parity) > - { > - case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; > - case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; > - case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; > - default: return -EINVAL; > - } > - > - info->params.encoding = new_encoding; > - info->params.crc_type = new_crctype; > - > - /* if network interface up, reprogram hardware */ > - if (info->netcount) { > - tty = tty_port_tty_get(&info->port); > - mgslpc_program_hw(info, tty); > - tty_kref_put(tty); > - } > - > - return 0; > -} > - > -/* > - * called by generic HDLC layer to send frame > - * > - * skb socket buffer containing HDLC frame > - * dev pointer to network device structure > - */ > -static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, > - struct net_device *dev) > -{ > - MGSLPC_INFO *info = dev_to_port(dev); > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk(KERN_INFO "%s:hdlc_xmit(%s)\n", __FILE__, dev->name); > - > - /* stop sending until this frame completes */ > - netif_stop_queue(dev); > - > - /* copy data to device buffers */ > - skb_copy_from_linear_data(skb, info->tx_buf, skb->len); > - info->tx_get = 0; > - info->tx_put = info->tx_count = skb->len; > - > - /* update network statistics */ > - dev->stats.tx_packets++; > - dev->stats.tx_bytes += skb->len; > - > - /* done with socket buffer, so free it */ > - dev_kfree_skb(skb); > - > - /* save start time for transmit timeout detection */ > - netif_trans_update(dev); > - > - /* start hardware transmitter if necessary */ > - spin_lock_irqsave(&info->lock, flags); > - if (!info->tx_active) { > - struct tty_struct *tty = tty_port_tty_get(&info->port); > - tx_start(info, tty); > - tty_kref_put(tty); > - } > - spin_unlock_irqrestore(&info->lock, flags); > - > - return NETDEV_TX_OK; > -} > - > -/* > - * called by network layer when interface enabled > - * claim resources and initialize hardware > - * > - * dev pointer to network device structure > - * > - * returns 0 if success, otherwise error code > - */ > -static int hdlcdev_open(struct net_device *dev) > -{ > - MGSLPC_INFO *info = dev_to_port(dev); > - struct tty_struct *tty; > - int rc; > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s:hdlcdev_open(%s)\n", __FILE__, dev->name); > - > - /* generic HDLC layer open processing */ > - rc = hdlc_open(dev); > - if (rc != 0) > - return rc; > - > - /* arbitrate between network and tty opens */ > - spin_lock_irqsave(&info->netlock, flags); > - if (info->port.count != 0 || info->netcount != 0) { > - printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); > - spin_unlock_irqrestore(&info->netlock, flags); > - return -EBUSY; > - } > - info->netcount=1; > - spin_unlock_irqrestore(&info->netlock, flags); > - > - tty = tty_port_tty_get(&info->port); > - /* claim resources and init adapter */ > - rc = startup(info, tty); > - if (rc != 0) { > - tty_kref_put(tty); > - spin_lock_irqsave(&info->netlock, flags); > - info->netcount=0; > - spin_unlock_irqrestore(&info->netlock, flags); > - return rc; > - } > - /* assert RTS and DTR, apply hardware settings */ > - info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; > - mgslpc_program_hw(info, tty); > - tty_kref_put(tty); > - > - /* enable network layer transmit */ > - netif_trans_update(dev); > - netif_start_queue(dev); > - > - /* inform generic HDLC layer of current DCD status */ > - spin_lock_irqsave(&info->lock, flags); > - get_signals(info); > - spin_unlock_irqrestore(&info->lock, flags); > - if (info->serial_signals & SerialSignal_DCD) > - netif_carrier_on(dev); > - else > - netif_carrier_off(dev); > - return 0; > -} > - > -/* > - * called by network layer when interface is disabled > - * shutdown hardware and release resources > - * > - * dev pointer to network device structure > - * > - * returns 0 if success, otherwise error code > - */ > -static int hdlcdev_close(struct net_device *dev) > -{ > - MGSLPC_INFO *info = dev_to_port(dev); > - struct tty_struct *tty = tty_port_tty_get(&info->port); > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s:hdlcdev_close(%s)\n", __FILE__, dev->name); > - > - netif_stop_queue(dev); > - > - /* shutdown adapter and release resources */ > - shutdown(info, tty); > - tty_kref_put(tty); > - hdlc_close(dev); > - > - spin_lock_irqsave(&info->netlock, flags); > - info->netcount=0; > - spin_unlock_irqrestore(&info->netlock, flags); > - > - return 0; > -} > - > -/* > - * called by network layer to process IOCTL call to network device > - * > - * dev pointer to network device structure > - * ifs pointer to network interface settings structure > - * > - * returns 0 if success, otherwise error code > - */ > -static int hdlcdev_wan_ioctl(struct net_device *dev, struct if_settings *ifs) > -{ > - const size_t size = sizeof(sync_serial_settings); > - sync_serial_settings new_line; > - sync_serial_settings __user *line = ifs->ifs_ifsu.sync; > - MGSLPC_INFO *info = dev_to_port(dev); > - unsigned int flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("%s:hdlcdev_ioctl(%s)\n", __FILE__, dev->name); > - > - /* return error if TTY interface open */ > - if (info->port.count) > - return -EBUSY; > - > - memset(&new_line, 0, size); > - > - switch (ifs->type) { > - case IF_GET_IFACE: /* return current sync_serial_settings */ > - > - ifs->type = IF_IFACE_SYNC_SERIAL; > - if (ifs->size < size) { > - ifs->size = size; /* data size wanted */ > - return -ENOBUFS; > - } > - > - flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | > - HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | > - HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | > - HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); > - > - switch (flags){ > - case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; > - case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; > - case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; > - case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; > - default: new_line.clock_type = CLOCK_DEFAULT; > - } > - > - new_line.clock_rate = info->params.clock_speed; > - new_line.loopback = info->params.loopback ? 1:0; > - > - if (copy_to_user(line, &new_line, size)) > - return -EFAULT; > - return 0; > - > - case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ > - > - if(!capable(CAP_NET_ADMIN)) > - return -EPERM; > - if (copy_from_user(&new_line, line, size)) > - return -EFAULT; > - > - switch (new_line.clock_type) > - { > - case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; > - case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; > - case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; > - case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; > - case CLOCK_DEFAULT: flags = info->params.flags & > - (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | > - HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | > - HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | > - HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; > - default: return -EINVAL; > - } > - > - if (new_line.loopback != 0 && new_line.loopback != 1) > - return -EINVAL; > - > - info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | > - HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | > - HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | > - HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); > - info->params.flags |= flags; > - > - info->params.loopback = new_line.loopback; > - > - if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) > - info->params.clock_speed = new_line.clock_rate; > - else > - info->params.clock_speed = 0; > - > - /* if network interface up, reprogram hardware */ > - if (info->netcount) { > - struct tty_struct *tty = tty_port_tty_get(&info->port); > - mgslpc_program_hw(info, tty); > - tty_kref_put(tty); > - } > - return 0; > - default: > - return hdlc_ioctl(dev, ifs); > - } > -} > - > -/* > - * called by network layer when transmit timeout is detected > - * > - * dev pointer to network device structure > - */ > -static void hdlcdev_tx_timeout(struct net_device *dev, unsigned int txqueue) > -{ > - MGSLPC_INFO *info = dev_to_port(dev); > - unsigned long flags; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("hdlcdev_tx_timeout(%s)\n", dev->name); > - > - dev->stats.tx_errors++; > - dev->stats.tx_aborted_errors++; > - > - spin_lock_irqsave(&info->lock, flags); > - tx_stop(info); > - spin_unlock_irqrestore(&info->lock, flags); > - > - netif_wake_queue(dev); > -} > - > -/* > - * called by device driver when transmit completes > - * reenable network layer transmit if stopped > - * > - * info pointer to device instance information > - */ > -static void hdlcdev_tx_done(MGSLPC_INFO *info) > -{ > - if (netif_queue_stopped(info->netdev)) > - netif_wake_queue(info->netdev); > -} > - > -/* > - * called by device driver when frame received > - * pass frame to network layer > - * > - * info pointer to device instance information > - * buf pointer to buffer contianing frame data > - * size count of data bytes in buf > - */ > -static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size) > -{ > - struct sk_buff *skb = dev_alloc_skb(size); > - struct net_device *dev = info->netdev; > - > - if (debug_level >= DEBUG_LEVEL_INFO) > - printk("hdlcdev_rx(%s)\n", dev->name); > - > - if (skb == NULL) { > - printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name); > - dev->stats.rx_dropped++; > - return; > - } > - > - skb_put_data(skb, buf, size); > - > - skb->protocol = hdlc_type_trans(skb, dev); > - > - dev->stats.rx_packets++; > - dev->stats.rx_bytes += size; > - > - netif_rx(skb); > -} > - > -static const struct net_device_ops hdlcdev_ops = { > - .ndo_open = hdlcdev_open, > - .ndo_stop = hdlcdev_close, > - .ndo_start_xmit = hdlc_start_xmit, > - .ndo_siocwandev = hdlcdev_wan_ioctl, > - .ndo_tx_timeout = hdlcdev_tx_timeout, > -}; > - > -/* > - * called by device driver when adding device instance > - * do generic HDLC initialization > - * > - * info pointer to device instance information > - * > - * returns 0 if success, otherwise error code > - */ > -static int hdlcdev_init(MGSLPC_INFO *info) > -{ > - int rc; > - struct net_device *dev; > - hdlc_device *hdlc; > - > - /* allocate and initialize network and HDLC layer objects */ > - > - dev = alloc_hdlcdev(info); > - if (dev == NULL) { > - printk(KERN_ERR "%s:hdlc device allocation failure\n", __FILE__); > - return -ENOMEM; > - } > - > - /* for network layer reporting purposes only */ > - dev->base_addr = info->io_base; > - dev->irq = info->irq_level; > - > - /* network layer callbacks and settings */ > - dev->netdev_ops = &hdlcdev_ops; > - dev->watchdog_timeo = 10 * HZ; > - dev->tx_queue_len = 50; > - > - /* generic HDLC layer callbacks and settings */ > - hdlc = dev_to_hdlc(dev); > - hdlc->attach = hdlcdev_attach; > - hdlc->xmit = hdlcdev_xmit; > - > - /* register objects with HDLC layer */ > - rc = register_hdlc_device(dev); > - if (rc) { > - printk(KERN_WARNING "%s:unable to register hdlc device\n", __FILE__); > - free_netdev(dev); > - return rc; > - } > - > - info->netdev = dev; > - return 0; > -} > - > -/* > - * called by device driver when removing device instance > - * do generic HDLC cleanup > - * > - * info pointer to device instance information > - */ > -static void hdlcdev_exit(MGSLPC_INFO *info) > -{ > - unregister_hdlc_device(info->netdev); > - free_netdev(info->netdev); > - info->netdev = NULL; > -} > - > -#endif /* CONFIG_HDLC */ > - > diff --git a/include/linux/cm4000_cs.h b/include/linux/cm4000_cs.h > deleted file mode 100644 > index ea4958e07a14..000000000000 > --- a/include/linux/cm4000_cs.h > +++ /dev/null > @@ -1,11 +0,0 @@ > -/* SPDX-License-Identifier: GPL-2.0 */ > -#ifndef _CM4000_H_ > -#define _CM4000_H_ > - > -#include > - > - > -#define DEVICE_NAME "cmm" > -#define MODULE_NAME "cm4000_cs" > - > -#endif /* _CM4000_H_ */ -- js suse labs