11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*********************************************************************
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Filename:      nsc-ircc.c
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version:       1.0
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Description:   Driver for the NSC PC'108 and PC'338 IrDA chipsets
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Status:        Stable.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author:        Dag Brattli <dagb@cs.uit.no>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Created at:    Sat Nov  7 21:43:15 1998
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modified at:   Wed Mar  1 11:29:34 2000
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modified by:   Dag Brattli <dagb@cs.uit.no>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Copyright (c) 1998 Actisys Corp., www.actisys.com
15ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes *     Copyright (c) 2000-2004 Jean Tourrilhes <jt@hpl.hp.com>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     All Rights Reserved
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     This program is free software; you can redistribute it and/or
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     modify it under the terms of the GNU General Public License as
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     published by the Free Software Foundation; either version 2 of
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     the License, or (at your option) any later version.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2396de0e252cedffad61b3cb5e05662c591898e69aJan Engelhardt *     Neither Dag Brattli nor University of Tromsø admit liability nor
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     provide warranty for any of this software. This material is
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     provided "AS-IS" and at no charge.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Notice that all functions that needs to access the chip in _any_
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     way, must save BSR register on entry, and restore it on exit.
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     It is _very_ important to follow this policy!
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *         __u8 bank;
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *         bank = inb(iobase+BSR);
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *         do_your_stuff_here();
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *         outb(bank, iobase+BSR);
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    If you find bugs in this file, its very likely that the same bug
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    will also be in w83977af_ir.c since the implementations are quite
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    similar.
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ********************************************************************/
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
465a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
55a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h>
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rtnetlink.h>
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dma-mapping.h>
58ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes#include <linux/pnp.h>
593b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov#include <linux/platform_device.h>
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h>
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h>
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/wrapper.h>
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/irda.h>
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/irda_device.h>
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "nsc-ircc.h"
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CHIP_IO_EXTENT 8
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BROKEN_DONGLE_ID
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *driver_name = "nsc-ircc";
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
763b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov/* Power Management */
773b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov#define NSC_IRCC_DRIVER_NAME                  "nsc-ircc"
783b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhovstatic int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state);
793b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhovstatic int nsc_ircc_resume(struct platform_device *dev);
803b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov
813b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhovstatic struct platform_driver nsc_ircc_driver = {
823b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	.suspend	= nsc_ircc_suspend,
833b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	.resume		= nsc_ircc_resume,
843b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	.driver		= {
853b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		.name	= NSC_IRCC_DRIVER_NAME,
863b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	},
873b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov};
883b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Module parameters */
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qos_mtt_bits = 0x07;  /* 1 ms or more */
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dongle_id;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Use BIOS settions by default, but user may supply module parameters */
940ed79c9b7dea5cd9a55589a495cf96f00cd037d9Jean Tourrilhesstatic unsigned int io[]  = { ~0, ~0, ~0, ~0, ~0 };
950ed79c9b7dea5cd9a55589a495cf96f00cd037d9Jean Tourrilhesstatic unsigned int irq[] = {  0,  0,  0,  0,  0 };
960ed79c9b7dea5cd9a55589a495cf96f00cd037d9Jean Tourrilhesstatic unsigned int dma[] = {  0,  0,  0,  0,  0 };
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info);
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info);
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info);
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info);
104c17f888f8fc2e47e2b4a51424f8ccf564ae87576Ingo Molnar#ifdef CONFIG_PNP
105ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhesstatic int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id);
106c17f888f8fc2e47e2b4a51424f8ccf564ae87576Ingo Molnar#endif
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These are the known NSC chips */
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic nsc_chip_t chips[] = {
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*  Name, {cfg registers}, chip id index reg, chip id expected value, revision mask */
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "PC87108", { 0x150, 0x398, 0xea }, 0x05, 0x10, 0xf0,
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  nsc_ircc_probe_108, nsc_ircc_init_108 },
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf8,
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  nsc_ircc_probe_338, nsc_ircc_init_338 },
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Contributed by Steffen Pingel - IBM X40 */
1162fd19a687c256fa4c4750465b9856e2c80660ec8Lamarque Vieira Souza	{ "PC8738x", { 0x164e, 0x4e, 0x2e }, 0x20, 0xf4, 0xff,
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Contributed by Jan Frey - IBM A30/A31 */
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff,
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
121d83561a4d67863b4aa297e8f598823dd4dfe855eBen Collins	/* IBM ThinkPads using PC8738x (T60/X60/Z60) */
122d83561a4d67863b4aa297e8f598823dd4dfe855eBen Collins	{ "IBM-PC8738x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
123d83561a4d67863b4aa297e8f598823dd4dfe855eBen Collins	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
124d83561a4d67863b4aa297e8f598823dd4dfe855eBen Collins	/* IBM ThinkPads using PC8394T (T43/R52/?) */
125d83561a4d67863b4aa297e8f598823dd4dfe855eBen Collins	{ "IBM-PC8394T", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf9, 0xff,
126d83561a4d67863b4aa297e8f598823dd4dfe855eBen Collins	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ NULL }
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1300ed79c9b7dea5cd9a55589a495cf96f00cd037d9Jean Tourrilhesstatic struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL };
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *dongle_types[] = {
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Differential serial interface",
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Differential serial interface",
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Reserved",
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Reserved",
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Sharp RY5HD01",
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Reserved",
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Single-ended serial interface",
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Consumer-IR only",
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"HP HSDL-2300, HP HSDL-3600/HSDL-3610",
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"IBM31T1100 or Temic TFDS6000/TFDS6500",
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Reserved",
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Reserved",
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"HP HSDL-1100/HSDL-2100",
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"HP HSDL-1100/HSDL-2100",
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Supports SIR Mode only",
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"No dongle connected",
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes/* PNP probing */
152ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhesstatic chipio_t pnp_info;
153ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhesstatic const struct pnp_device_id nsc_ircc_pnp_table[] = {
154ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	{ .id = "NSC6001", .driver_data = 0 },
15502307080622da0312f2ede0f9c0ac779a1cc4f9aVille Syrjala	{ .id = "HWPC224", .driver_data = 0 },
1561fa98174ba980b2826edd1e4632a17916dfdb4faMatthew Garrett	{ .id = "IBM0071", .driver_data = NSC_FORCE_DONGLE_TYPE9 },
157ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	{ }
158ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes};
159ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
160ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean TourrilhesMODULE_DEVICE_TABLE(pnp, nsc_ircc_pnp_table);
161ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
162ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhesstatic struct pnp_driver nsc_ircc_pnp_driver = {
163c17f888f8fc2e47e2b4a51424f8ccf564ae87576Ingo Molnar#ifdef CONFIG_PNP
164ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	.name = "nsc-ircc",
165ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	.id_table = nsc_ircc_pnp_table,
166ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	.probe = nsc_ircc_pnp_probe,
167c17f888f8fc2e47e2b4a51424f8ccf564ae87576Ingo Molnar#endif
168ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes};
169ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Some prototypes */
171ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhesstatic int  nsc_ircc_open(chipio_t *info);
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int  nsc_ircc_close(struct nsc_ircc_cb *self);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int  nsc_ircc_setup(chipio_t *info);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nsc_ircc_pio_receive(struct nsc_ircc_cb *self);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int  nsc_ircc_dma_receive(struct nsc_ircc_cb *self);
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int  nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase);
1776518bbb803fe02b15a3211c8db2afdff0ac4f808Stephen Hemmingerstatic netdev_tx_t  nsc_ircc_hard_xmit_sir(struct sk_buff *skb,
1786518bbb803fe02b15a3211c8db2afdff0ac4f808Stephen Hemminger						 struct net_device *dev);
1796518bbb803fe02b15a3211c8db2afdff0ac4f808Stephen Hemmingerstatic netdev_tx_t  nsc_ircc_hard_xmit_fir(struct sk_buff *skb,
1806518bbb803fe02b15a3211c8db2afdff0ac4f808Stephen Hemminger						 struct net_device *dev);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int  nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 baud);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int  nsc_ircc_is_receiving(struct nsc_ircc_cb *self);
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int  nsc_ircc_read_dongle_id (int iobase);
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nsc_ircc_init_dongle_interface (int iobase, int dongle_id);
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int  nsc_ircc_net_open(struct net_device *dev);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int  nsc_ircc_net_close(struct net_device *dev);
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int  nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
192ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes/* Globals */
193ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhesstatic int pnp_registered;
194ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhesstatic int pnp_succeeded;
195ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_init ()
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Initialize chip. Just try to find out how many chips we are dealing with
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    and where they are
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init nsc_ircc_init(void)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chipio_t info;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nsc_chip_t *chip;
206ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	int ret;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cfg_base;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cfg, id;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int reg;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 0;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2123b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	ret = platform_driver_register(&nsc_ircc_driver);
2133b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov        if (ret) {
2143b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov                IRDA_ERROR("%s, Can't register driver!\n", driver_name);
2153b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov                return ret;
2163b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov        }
2173b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov
218ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes 	/* Register with PnP subsystem to detect disable ports */
219ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	ret = pnp_register_driver(&nsc_ircc_pnp_driver);
220ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
221803d0abb3dcfc93701c8a8dc7f2968a47271214cBjorn Helgaas 	if (!ret)
222ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes 		pnp_registered = 1;
223ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
224ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	ret = -ENODEV;
225ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Probe for all the NSC chipsets we know about */
227ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	for (chip = chips; chip->name ; chip++) {
228a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison		IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __func__,
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   chip->name);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Try all config registers for this chip */
232ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes		for (cfg = 0; cfg < ARRAY_SIZE(chip->cfg); cfg++) {
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cfg_base = chip->cfg[cfg];
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!cfg_base)
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Read index register */
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			reg = inb(cfg_base);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (reg == 0xff) {
240a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison				IRDA_DEBUG(2, "%s() no chip at 0x%03x\n", __func__, cfg_base);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Read chip identification register */
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(chip->cid_index, cfg_base);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			id = inb(cfg_base+1);
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((id & chip->cid_mask) == chip->cid_value) {
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n",
249a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison					   __func__, chip->name, id & ~chip->cid_mask);
250ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
251ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes				/*
252ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes				 * If we found a correct PnP setting,
253ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes				 * we first try it.
254ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes				 */
255ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes				if (pnp_succeeded) {
256ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					memset(&info, 0, sizeof(chipio_t));
257ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					info.cfg_base = cfg_base;
258ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					info.fir_base = pnp_info.fir_base;
259ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					info.dma = pnp_info.dma;
260ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					info.irq = pnp_info.irq;
261ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
262ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					if (info.fir_base < 0x2000) {
263ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes						IRDA_MESSAGE("%s, chip->init\n", driver_name);
264ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes						chip->init(chip, &info);
265ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					} else
266ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes						chip->probe(chip, &info);
267ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
268ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					if (nsc_ircc_open(&info) >= 0)
269ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes						ret = 0;
270ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes				}
271ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
272ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes				/*
273ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes				 * Opening based on PnP values failed.
274ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes				 * Let's fallback to user values, or probe
275ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes				 * the chip.
276ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes				 */
277ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes				if (ret) {
278ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					IRDA_DEBUG(2, "%s, PnP init failed\n", driver_name);
279ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					memset(&info, 0, sizeof(chipio_t));
280ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					info.cfg_base = cfg_base;
281ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					info.fir_base = io[i];
282ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					info.dma = dma[i];
283ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					info.irq = irq[i];
284ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
285ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					/*
286ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					 * If the user supplies the base address, then
287ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					 * we init the chip, if not we probe the values
288ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					 * set by the BIOS
289ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					 */
290ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					if (io[i] < 0x2000) {
291ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes						chip->init(chip, &info);
292ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					} else
293ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes						chip->probe(chip, &info);
294ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
295ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes					if (nsc_ircc_open(&info) >= 0)
296ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes						ret = 0;
297ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes				}
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				i++;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
300a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison				IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __func__, id);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
303ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	}
304ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
305ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	if (ret) {
3063b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		platform_driver_unregister(&nsc_ircc_driver);
307ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes		pnp_unregister_driver(&nsc_ircc_pnp_driver);
308ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes		pnp_registered = 0;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_cleanup ()
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Close all configured chips
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit nsc_ircc_cleanup(void)
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
324ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	for (i = 0; i < ARRAY_SIZE(dev_self); i++) {
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dev_self[i])
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nsc_ircc_close(dev_self[i]);
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
328ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
3293b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	platform_driver_unregister(&nsc_ircc_driver);
3303b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov
331ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	if (pnp_registered)
332ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes 		pnp_unregister_driver(&nsc_ircc_pnp_driver);
333ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
334ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	pnp_registered = 0;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
337c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemmingerstatic const struct net_device_ops nsc_ircc_sir_ops = {
338c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger	.ndo_open       = nsc_ircc_net_open,
339c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger	.ndo_stop       = nsc_ircc_net_close,
340c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger	.ndo_start_xmit = nsc_ircc_hard_xmit_sir,
341c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger	.ndo_do_ioctl   = nsc_ircc_net_ioctl,
342c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger};
343c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger
344c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemmingerstatic const struct net_device_ops nsc_ircc_fir_ops = {
345c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger	.ndo_open       = nsc_ircc_net_open,
346c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger	.ndo_stop       = nsc_ircc_net_close,
347c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger	.ndo_start_xmit = nsc_ircc_hard_xmit_fir,
348c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger	.ndo_do_ioctl   = nsc_ircc_net_ioctl,
349c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger};
350c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_open (iobase, irq)
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Open driver instance
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
357ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhesstatic int __init nsc_ircc_open(chipio_t *info)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nsc_ircc_cb *self;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *ret;
362ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	int err, chip_index;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
364a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	IRDA_DEBUG(2, "%s()\n", __func__);
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
366ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
367ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes 	for (chip_index = 0; chip_index < ARRAY_SIZE(dev_self); chip_index++) {
368ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes		if (!dev_self[chip_index])
369ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes			break;
370ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	}
371ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
372ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	if (chip_index == ARRAY_SIZE(dev_self)) {
373a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison		IRDA_ERROR("%s(), maximum number of supported chips reached!\n", __func__);
374ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes		return -ENOMEM;
375ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	}
376ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_MESSAGE("%s, Found chip at base=0x%03x\n", driver_name,
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     info->cfg_base);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((nsc_ircc_setup(info)) == -1)
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = alloc_irdadev(sizeof(struct nsc_ircc_cb));
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev == NULL) {
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_ERROR("%s(), can't allocate memory for "
388a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   "control block!\n", __func__);
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3924cf1653aa90c6320dc8032443b5e322820aa28b1Wang Chen	self = netdev_priv(dev);
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->netdev = dev;
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&self->lock);
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Need to store self somewhere */
397ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	dev_self[chip_index] = self;
398ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	self->index = chip_index;
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize IO */
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->io.cfg_base  = info->cfg_base;
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->io.fir_base  = info->fir_base;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        self->io.irq       = info->irq;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        self->io.fir_ext   = CHIP_IO_EXTENT;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        self->io.dma       = info->dma;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        self->io.fifo_size = 32;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reserve the ioports that we need */
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name);
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ret) {
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_WARNING("%s(), can't get iobase of 0x%03x\n",
412a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			     __func__, self->io.fir_base);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENODEV;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out1;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize QoS for this device */
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irda_init_max_qos_capabilies(&self->qos);
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The only value we must override it the baudrate */
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IR_115200|IR_576000|IR_1152000 |(IR_4000000 << 8);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->qos.min_turn_time.bits = qos_mtt_bits;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irda_qos_bits_to_value(&self->qos);
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->rx_buff.truesize = 14384;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_buff.truesize = 14384;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Allocate memory if needed */
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->rx_buff.head =
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dma_alloc_coherent(NULL, self->rx_buff.truesize,
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   &self->rx_buff_dma, GFP_KERNEL);
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (self->rx_buff.head == NULL) {
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOMEM;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out2;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(self->rx_buff.head, 0, self->rx_buff.truesize);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_buff.head =
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dma_alloc_coherent(NULL, self->tx_buff.truesize,
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   &self->tx_buff_dma, GFP_KERNEL);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (self->tx_buff.head == NULL) {
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOMEM;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out3;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(self->tx_buff.head, 0, self->tx_buff.truesize);
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->rx_buff.in_frame = FALSE;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->rx_buff.state = OUTSIDE_FRAME;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_buff.data = self->tx_buff.head;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->rx_buff.data = self->rx_buff.head;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reset Tx queue info */
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_fifo.tail = self->tx_buff.head;
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Override the network functions we need to use */
461c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger	dev->netdev_ops = &nsc_ircc_sir_ops;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = register_netdev(dev);
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err) {
465a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison		IRDA_ERROR("%s(), register_netdev() failed!\n", __func__);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out4;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check if user has supplied a valid dongle id or not */
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((dongle_id <= 0) ||
472ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	    (dongle_id >= ARRAY_SIZE(dongle_types))) {
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_MESSAGE("%s, Found dongle: %s\n", driver_name,
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     dongle_types[dongle_id]);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_MESSAGE("%s, Using dongle: %s\n", driver_name,
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     dongle_types[dongle_id]);
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->io.dongle_id = dongle_id;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4853b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov 	self->pldev = platform_device_register_simple(NSC_IRCC_DRIVER_NAME,
4863b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov 						      self->index, NULL, 0);
4873b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov 	if (IS_ERR(self->pldev)) {
4883b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov 		err = PTR_ERR(self->pldev);
4893b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov 		goto out5;
4903b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov 	}
4913b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov 	platform_set_drvdata(self->pldev, self);
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
493ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	return chip_index;
4943b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov
4953b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov out5:
4963b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov 	unregister_netdev(dev);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out4:
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_free_coherent(NULL, self->tx_buff.truesize,
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  self->tx_buff.head, self->tx_buff_dma);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out3:
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_free_coherent(NULL, self->rx_buff.truesize,
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  self->rx_buff.head, self->rx_buff_dma);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out2:
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(self->io.fir_base, self->io.fir_ext);
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out1:
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
507ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	dev_self[chip_index] = NULL;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_close (self)
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Close driver instance
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __exit nsc_ircc_close(struct nsc_ircc_cb *self)
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int iobase;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	IRDA_DEBUG(4, "%s()\n", __func__);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self != NULL, return -1;);
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        iobase = self->io.fir_base;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5273b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	platform_device_unregister(self->pldev);
5283b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Remove netdevice */
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_netdev(self->netdev);
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Release the PORT that this driver is using */
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_DEBUG(4, "%s(), Releasing Region %03x\n",
534a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison		   __func__, self->io.fir_base);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(self->io.fir_base, self->io.fir_ext);
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (self->tx_buff.head)
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dma_free_coherent(NULL, self->tx_buff.truesize,
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  self->tx_buff.head, self->tx_buff_dma);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (self->rx_buff.head)
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dma_free_coherent(NULL, self->rx_buff.truesize,
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  self->rx_buff.head, self->rx_buff_dma);
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_self[self->index] = NULL;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(self->netdev);
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_init_108 (iobase, cfg_base, irq, dma)
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Initialize the NSC '108 chip
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info)
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cfg_base = info->cfg_base;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 temp=0;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(2, cfg_base);      /* Mode Control Register (MCTL) */
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x00, cfg_base+1); /* Disable device */
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Base Address and Interrupt Control Register (BAIC) */
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_108_BAIC, cfg_base);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (info->fir_base) {
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x3e8: outb(0x14, cfg_base+1); break;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x2e8: outb(0x15, cfg_base+1); break;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x3f8: outb(0x16, cfg_base+1); break;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x2f8: outb(0x17, cfg_base+1); break;
572a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	default: IRDA_ERROR("%s(), invalid base_address", __func__);
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Control Signal Routing Register (CSRT) */
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (info->irq) {
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 3:  temp = 0x01; break;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 4:  temp = 0x02; break;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 5:  temp = 0x03; break;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 7:  temp = 0x04; break;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 9:  temp = 0x05; break;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 11: temp = 0x06; break;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 15: temp = 0x07; break;
584a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	default: IRDA_ERROR("%s(), invalid irq", __func__);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_108_CSRT, cfg_base);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (info->dma) {
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0: outb(0x08+temp, cfg_base+1); break;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1: outb(0x10+temp, cfg_base+1); break;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 3: outb(0x18+temp, cfg_base+1); break;
592a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	default: IRDA_ERROR("%s(), invalid dma", __func__);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_108_MCTL, cfg_base);      /* Mode Control Register (MCTL) */
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x03, cfg_base+1); /* Enable device */
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_probe_108 (chip, info)
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info)
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cfg_base = info->cfg_base;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int reg;
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read address and interrupt control register (BAIC) */
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_108_BAIC, cfg_base);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg = inb(cfg_base+1);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (reg & 0x03) {
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->fir_base = 0x3e8;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->fir_base = 0x2e8;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->fir_base = 0x3f8;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 3:
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->fir_base = 0x2f8;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->sir_base = info->fir_base;
631a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __func__,
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   info->fir_base);
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read control signals routing register (CSRT) */
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_108_CSRT, cfg_base);
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg = inb(cfg_base+1);
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (reg & 0x07) {
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->irq = -1;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->irq = 3;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->irq = 4;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 3:
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->irq = 5;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 4:
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->irq = 7;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 5:
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->irq = 9;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 6:
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->irq = 11;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 7:
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->irq = 15;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
664a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	IRDA_DEBUG(2, "%s(), probing irq=%d\n", __func__, info->irq);
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Currently we only read Rx DMA but it will also be used for Tx */
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch ((reg >> 3) & 0x03) {
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->dma = -1;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->dma = 0;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->dma = 1;
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 3:
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->dma = 3;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
681a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	IRDA_DEBUG(2, "%s(), probing dma=%d\n", __func__, info->dma);
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read mode control register (MCTL) */
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_108_MCTL, cfg_base);
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg = inb(cfg_base+1);
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->enabled = reg & 0x01;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->suspended = !((reg >> 1) & 0x01);
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_init_338 (chip, info)
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Initialize the NSC '338 chip. Remember that the 87338 needs two
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    consecutive writes to the data registers while CPU interrupts are
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    disabled. The 97338 does not require this, but shouldn't be any
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    harm if we do it anyway.
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info)
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* No init yet */
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_probe_338 (chip, info)
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info)
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cfg_base = info->cfg_base;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int reg, com = 0;
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pnp;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
72025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* Read function enable register (FER) */
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_338_FER, cfg_base);
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg = inb(cfg_base+1);
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->enabled = (reg >> 2) & 0x01;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check if we are in Legacy or PnP mode */
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_338_PNP0, cfg_base);
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg = inb(cfg_base+1);
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pnp = (reg >> 3) & 0x01;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pnp) {
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(2, "(), Chip is in PnP mode\n");
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x46, cfg_base);
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = (inb(cfg_base+1) & 0xfe) << 2;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x47, cfg_base);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg |= ((inb(cfg_base+1) & 0xfc) << 8);
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->fir_base = reg;
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Read function address register (FAR) */
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(CFG_338_FAR, cfg_base);
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = inb(cfg_base+1);
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch ((reg >> 4) & 0x03) {
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0:
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info->fir_base = 0x3f8;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 1:
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info->fir_base = 0x2f8;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 2:
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			com = 3;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 3:
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			com = 4;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (com) {
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch ((reg >> 6) & 0x03) {
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case 0:
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (com == 3)
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					info->fir_base = 0x3e8;
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					info->fir_base = 0x2e8;
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case 1:
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (com == 3)
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					info->fir_base = 0x338;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					info->fir_base = 0x238;
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case 2:
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (com == 3)
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					info->fir_base = 0x2e8;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					info->fir_base = 0x2e0;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case 3:
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (com == 3)
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					info->fir_base = 0x220;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					info->fir_base = 0x228;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->sir_base = info->fir_base;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read PnP register 1 (PNP1) */
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_338_PNP1, cfg_base);
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg = inb(cfg_base+1);
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->irq = reg >> 4;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read PnP register 3 (PNP3) */
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_338_PNP3, cfg_base);
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg = inb(cfg_base+1);
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->dma = (reg & 0x07) - 1;
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read power and test register (PTR) */
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_338_PTR, cfg_base);
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg = inb(cfg_base+1);
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->suspended = reg & 0x01;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_init_39x (chip, info)
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Now that we know it's a '39x (see probe below), we need to
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    configure it so we can use it.
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The NSC '338 chip is a Super I/O chip with a "bank" architecture,
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the configuration of the different functionality (serial, parallel,
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * floppy...) are each in a different bank (Logical Device Number).
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The base address, irq and dma configuration registers are common
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to all functionalities (index 0x30 to 0x7F).
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There is only one configuration register specific to the
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * serial port, CFG_39X_SPC.
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * JeanII
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note : this code was written by Jan Frey <janfrey@web.de>
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info)
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cfg_base = info->cfg_base;
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int enabled;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8357f927fcc2fd1575d01efb4b76665975007945690Alexey Dobriyan	/* User is sure about his config... accept it. */
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_DEBUG(2, "%s(): nsc_ircc_init_39x (user settings): "
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   "io=0x%04x, irq=%d, dma=%d\n",
838a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison		   __func__, info->fir_base, info->irq, info->dma);
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Access bank for SP2 */
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_39X_LDN, cfg_base);
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x02, cfg_base+1);
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Configure SP2 */
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We want to enable the device if not enabled */
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_39X_ACT, cfg_base);
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enabled = inb(cfg_base+1) & 0x01;
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!enabled) {
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Enable the device */
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(CFG_39X_SIOCF1, cfg_base);
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x01, cfg_base+1);
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* May want to update info->enabled. Jean II */
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Enable UART bank switching (bit 7) ; Sets the chip to normal
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * power mode (wake up from sleep mode) (bit 1) */
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_39X_SPC, cfg_base);
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x82, cfg_base+1);
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_probe_39x (chip, info)
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Test if we really have a '39x chip at the given address
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note : this code was written by Jan Frey <janfrey@web.de>
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info)
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cfg_base = info->cfg_base;
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int reg1, reg2, irq, irqt, dma1, dma2;
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int enabled, susp;
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_DEBUG(2, "%s(), nsc_ircc_probe_39x, base=%d\n",
879a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison		   __func__, cfg_base);
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* This function should be executed with irq off to avoid
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * another driver messing with the Super I/O bank - Jean II */
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Access bank for SP2 */
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_39X_LDN, cfg_base);
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x02, cfg_base+1);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read infos about SP2 ; store in info struct */
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_39X_BASEH, cfg_base);
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg1 = inb(cfg_base+1);
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_39X_BASEL, cfg_base);
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg2 = inb(cfg_base+1);
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->fir_base = (reg1 << 8) | reg2;
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_39X_IRQNUM, cfg_base);
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irq = inb(cfg_base+1);
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_39X_IRQSEL, cfg_base);
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irqt = inb(cfg_base+1);
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->irq = irq;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_39X_DMA0, cfg_base);
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma1 = inb(cfg_base+1);
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_39X_DMA1, cfg_base);
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma2 = inb(cfg_base+1);
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->dma = dma1 -1;
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_39X_ACT, cfg_base);
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->enabled = enabled = inb(cfg_base+1) & 0x01;
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_39X_SPC, cfg_base);
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	susp = 1 - ((inb(cfg_base+1) & 0x02) >> 1);
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
913a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	IRDA_DEBUG(2, "%s(): io=0x%02x%02x, irq=%d (type %d), rxdma=%d, txdma=%d, enabled=%d (suspended=%d)\n", __func__, reg1,reg2,irq,irqt,dma1,dma2,enabled,susp);
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Configure SP2 */
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We want to enable the device if not enabled */
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_39X_ACT, cfg_base);
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enabled = inb(cfg_base+1) & 0x01;
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!enabled) {
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Enable the device */
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(CFG_39X_SIOCF1, cfg_base);
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x01, cfg_base+1);
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* May want to update info->enabled. Jean II */
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Enable UART bank switching (bit 7) ; Sets the chip to normal
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * power mode (wake up from sleep mode) (bit 1) */
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(CFG_39X_SPC, cfg_base);
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x82, cfg_base+1);
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
936c17f888f8fc2e47e2b4a51424f8ccf564ae87576Ingo Molnar#ifdef CONFIG_PNP
937ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes/* PNP probing */
938ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhesstatic int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id)
939ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes{
940ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	memset(&pnp_info, 0, sizeof(chipio_t));
941ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	pnp_info.irq = -1;
942ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	pnp_info.dma = -1;
943ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	pnp_succeeded = 1;
944ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
9451fa98174ba980b2826edd1e4632a17916dfdb4faMatthew Garrett	if (id->driver_data & NSC_FORCE_DONGLE_TYPE9)
9461fa98174ba980b2826edd1e4632a17916dfdb4faMatthew Garrett		dongle_id = 0x9;
9471fa98174ba980b2826edd1e4632a17916dfdb4faMatthew Garrett
9481fa98174ba980b2826edd1e4632a17916dfdb4faMatthew Garrett	/* There doesn't seem to be any way of getting the cfg_base.
949ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	 * On my box, cfg_base is in the PnP descriptor of the
950ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	 * motherboard. Oh well... Jean II */
951ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
952ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	if (pnp_port_valid(dev, 0) &&
953ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes		!(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED))
954ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes		pnp_info.fir_base = pnp_port_start(dev, 0);
955ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
956ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	if (pnp_irq_valid(dev, 0) &&
957ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes		!(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED))
958ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes		pnp_info.irq = pnp_irq(dev, 0);
959ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
960ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	if (pnp_dma_valid(dev, 0) &&
961ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes		!(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED))
962ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes		pnp_info.dma = pnp_dma(dev, 0);
963ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
964ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	IRDA_DEBUG(0, "%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n",
965a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison		   __func__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma);
966ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
967ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	if((pnp_info.fir_base == 0) ||
968ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	   (pnp_info.irq == -1) || (pnp_info.dma == -1)) {
969ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes		/* Returning an error will disable the device. Yuck ! */
970ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes		//return -EINVAL;
971ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes		pnp_succeeded = 0;
972ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	}
973ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
974ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes	return 0;
975ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes}
976c17f888f8fc2e47e2b4a51424f8ccf564ae87576Ingo Molnar#endif
977ec4f32d550b94b4b66c9c7689bc09c6b32c8e82eJean Tourrilhes
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_setup (info)
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Returns non-negative on success.
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_setup(chipio_t *info)
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int version;
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int iobase = info->fir_base;
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read the Module ID */
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK3);
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	version = inb(iobase+MID);
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_DEBUG(2, "%s() Driver %s Found chip version %02x\n",
994a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison		   __func__, driver_name, version);
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Should be 0x2? */
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (0x20 != (version & 0xf0)) {
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_ERROR("%s, Wrong chip version %02x\n",
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   driver_name, version);
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Switch to advanced mode */
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK2);
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(ECR1_EXT_SL, iobase+ECR1);
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x03, iobase+LCR); 	/* 8 bit word length */
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(MCR_SIR, iobase+MCR); 	/* Start at SIR-mode, also clears LSR*/
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set FIFO size to 32 */
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK2);
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* IRCR2: FEND_MD is not set */
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK5);
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 	outb(0x02, iobase+4);
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make sure that some defaults are OK */
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK6);
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x20, iobase+0); /* Set 32 bits FIR CRC */
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x0a, iobase+1); /* Set MIR pulse width */
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x0d, iobase+2); /* Set SIR pulse width to 1.6us */
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Enable receive interrupts */
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(IER_RXHDL_IE, iobase+IER);
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_read_dongle_id (void)
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to read dongle indentification. This procedure needs to be executed
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * once after power-on/reset. It also needs to be used whenever you suspect
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that the user may have plugged/unplugged the IrDA Dongle.
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_read_dongle_id (int iobase)
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dongle_id;
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 bank;
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bank = inb(iobase+BSR);
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Select Bank 7 */
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK7);
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x00, iobase+7);
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* ID0, 1, and 2 are pulled up/down very slowly */
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(50);
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* IRCFG1: read the ID bits */
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dongle_id = inb(iobase+4) & 0x0f;
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef BROKEN_DONGLE_ID
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dongle_id == 0x0a)
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dongle_id = 0x09;
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Go back to  bank 0 before returning */
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bank, iobase+BSR);
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dongle_id;
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_init_dongle_interface (iobase, dongle_id)
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     This function initializes the dongle for the transceiver that is
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     used. This procedure needs to be executed once after
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     power-on/reset. It also needs to be used whenever you suspect that
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     the dongle is changed.
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nsc_ircc_init_dongle_interface (int iobase, int dongle_id)
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bank;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save current bank */
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bank = inb(iobase+BSR);
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Select Bank 7 */
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK7);
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* IRCFG4: set according to dongle_id */
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (dongle_id) {
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x00: /* same as */
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x01: /* Differential serial interface */
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
1098a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x02: /* same as */
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x03: /* Reserved */
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
1103a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x04: /* Sharp RY5HD01 */
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x05: /* Reserved, but this is what the Thinkpad reports */
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
1109a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x06: /* Single-ended serial interface */
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
1113a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x07: /* Consumer-IR only */
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n",
1117a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s\n",
1121a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x28, iobase+7); /* Set irsl[0-2] as output */
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0A: /* same as */
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0B: /* Reserved */
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
1129a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0C: /* same as */
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Set irsl0 as input, irsl[1-2] as output, and separate
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * inputs are used for SIR and MIR/FIR
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x48, iobase+7);
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0E: /* Supports SIR Mode only */
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x28, iobase+7); /* Set irsl[0-2] as output */
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0F: /* No dongle connected */
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s\n",
1144a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch_bank(iobase, BANK0);
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x62, iobase+MCR);
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), invalid dongle_id %#x",
1151a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_id);
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* IRCFG1: IRSL1 and 2 are set to IrDA mode */
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x00, iobase+4);
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore bank register */
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bank, iobase+BSR);
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* set_up_dongle_interface */
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_change_dongle_speed (iobase, speed, dongle_id)
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Change speed of the attach dongle
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id)
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 bank;
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save current bank */
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bank = inb(iobase+BSR);
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Select Bank 7 */
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK7);
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* IRCFG1: set according to dongle_id */
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (dongle_id) {
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x00: /* same as */
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x01: /* Differential serial interface */
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
1183a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x02: /* same as */
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x03: /* Reserved */
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
1188a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x04: /* Sharp RY5HD01 */
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x05: /* Reserved */
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
1194a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x06: /* Single-ended serial interface */
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
1198a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x07: /* Consumer-IR only */
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n",
1202a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s\n",
1206a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x00, iobase+4);
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (speed > 115200)
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(0x01, iobase+4);
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x01, iobase+4);
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (speed == 4000000) {
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* There was a cli() there, but we now are already
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * under spin_lock_irqsave() - JeanII */
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(0x81, iobase+4);
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(0x80, iobase+4);
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(0x00, iobase+4);
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0A: /* same as */
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0B: /* Reserved */
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
1225a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0C: /* same as */
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0E: /* Supports SIR Mode only */
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0F: /* No dongle connected */
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n",
1234a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, dongle_types[dongle_id]);
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch_bank(iobase, BANK0);
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x62, iobase+MCR);
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1240a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison		IRDA_DEBUG(0, "%s(), invalid data_rate\n", __func__);
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore bank register */
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bank, iobase+BSR);
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_change_speed (self, baud)
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Change the speed of the device
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function *must* be called with irq off and spin-lock.
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed)
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = self->netdev;
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 mcr = MCR_SIR;
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int iobase;
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 bank;
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 ier;                  /* Interrupt enable register */
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	IRDA_DEBUG(2, "%s(), speed=%d\n", __func__, speed);
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self != NULL, return 0;);
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iobase = self->io.fir_base;
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Update accounting for new speed */
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->io.speed = speed;
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save current bank */
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bank = inb(iobase+BSR);
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Disable interrupts */
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, iobase+IER);
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Select Bank 2 */
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK2);
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x00, iobase+BGDH);
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (speed) {
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 9600:   outb(0x0c, iobase+BGDL); break;
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 19200:  outb(0x06, iobase+BGDL); break;
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 38400:  outb(0x03, iobase+BGDL); break;
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 57600:  outb(0x02, iobase+BGDL); break;
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 115200: outb(0x01, iobase+BGDL); break;
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 576000:
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch_bank(iobase, BANK5);
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* IRCR2: MDRS is set */
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(inb(iobase+4) | 0x04, iobase+4);
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mcr = MCR_MIR;
1294a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison		IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __func__);
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1152000:
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mcr = MCR_MIR;
1298a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison		IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", __func__);
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 4000000:
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mcr = MCR_FIR;
1302a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison		IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", __func__);
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mcr = MCR_FIR;
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(0, "%s(), unknown baud rate of %d\n",
1307a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__, speed);
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set appropriate speed mode */
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(mcr | MCR_TX_DFR, iobase+MCR);
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Give some hits to the transceiver */
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nsc_ircc_change_dongle_speed(iobase, speed, self->io.dongle_id);
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set FIFO threshold to TX17, RX16 */
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x00, iobase+FCR);
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(FCR_FIFO_EN, iobase+FCR);
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(FCR_RXTH|     /* Set Rx FIFO threshold */
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     FCR_TXTH|     /* Set Tx FIFO threshold */
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     FCR_TXSR|     /* Reset Tx FIFO */
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     FCR_RXSR|     /* Reset Rx FIFO */
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     FCR_FIFO_EN,  /* Enable FIFOs */
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     iobase+FCR);
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set FIFO size to 32 */
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK2);
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Enable some interrupts so we can receive frames */
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (speed > 115200) {
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Install FIR xmit handler */
1337c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger		dev->netdev_ops = &nsc_ircc_fir_ops;
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ier = IER_SFIF_IE;
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nsc_ircc_dma_receive(self);
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Install SIR xmit handler */
1342c279b8c996e99a3fca7806986415263f840b2fa1Stephen Hemminger		dev->netdev_ops = &nsc_ircc_sir_ops;
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ier = IER_RXHDL_IE;
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set our current interrupt mask */
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(ier, iobase+IER);
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore BSR */
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bank, iobase+BSR);
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make sure interrupt handlers keep the proper interrupt mask */
1352807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet	return ier;
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_hard_xmit (skb, dev)
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Transmit the frame!
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
13616518bbb803fe02b15a3211c8db2afdff0ac4f808Stephen Hemmingerstatic netdev_tx_t nsc_ircc_hard_xmit_sir(struct sk_buff *skb,
13626518bbb803fe02b15a3211c8db2afdff0ac4f808Stephen Hemminger						struct net_device *dev)
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nsc_ircc_cb *self;
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int iobase;
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__s32 speed;
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 bank;
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13704cf1653aa90c6320dc8032443b5e322820aa28b1Wang Chen	self = netdev_priv(dev);
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1372ec634fe328182a1a098585bfc7b69e5042bdb08dPatrick McHardy	IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iobase = self->io.fir_base;
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make sure tests *& speed change are atomic */
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&self->lock, flags);
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check if we need to change the speed */
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	speed = irda_get_next_speed(skb);
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((speed != self->io.speed) && (speed != -1)) {
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check for empty frame. */
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!skb->len) {
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* If we just sent a frame, we get called before
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * the last bytes get out (because of the SIR FIFO).
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * If this is the case, let interrupt handler change
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * the speed itself... Jean II */
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (self->io.direction == IO_RECV) {
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				nsc_ircc_change_speed(self, speed);
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* TODO : For SIR->SIR, the next packet
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * may get corrupted - Jean II */
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				netif_wake_queue(dev);
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				self->new_speed = speed;
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Queue will be restarted after speed change
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * to make sure packets gets through the
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * proper xmit handler - Jean II */
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->trans_start = jiffies;
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock_irqrestore(&self->lock, flags);
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_kfree_skb(skb);
14046ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy			return NETDEV_TX_OK;
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			self->new_speed = speed;
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save current bank */
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bank = inb(iobase+BSR);
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_buff.data = self->tx_buff.head;
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   self->tx_buff.truesize);
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1417af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger	dev->stats.tx_bytes += self->tx_buff.len;
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Add interrupt on tx low level (will fire immediately) */
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(IER_TXLDL_IE, iobase+IER);
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore bank register */
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bank, iobase+BSR);
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->trans_start = jiffies;
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&self->lock, flags);
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_kfree_skb(skb);
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14316ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy	return NETDEV_TX_OK;
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14346518bbb803fe02b15a3211c8db2afdff0ac4f808Stephen Hemmingerstatic netdev_tx_t nsc_ircc_hard_xmit_fir(struct sk_buff *skb,
14356518bbb803fe02b15a3211c8db2afdff0ac4f808Stephen Hemminger						struct net_device *dev)
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nsc_ircc_cb *self;
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int iobase;
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__s32 speed;
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 bank;
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int mtt, diff;
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14444cf1653aa90c6320dc8032443b5e322820aa28b1Wang Chen	self = netdev_priv(dev);
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iobase = self->io.fir_base;
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make sure tests *& speed change are atomic */
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&self->lock, flags);
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check if we need to change the speed */
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	speed = irda_get_next_speed(skb);
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((speed != self->io.speed) && (speed != -1)) {
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check for empty frame. */
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!skb->len) {
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* If we are currently transmitting, defer to
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * interrupt handler. - Jean II */
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(self->tx_fifo.len == 0) {
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				nsc_ircc_change_speed(self, speed);
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				netif_wake_queue(dev);
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				self->new_speed = speed;
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Keep queue stopped :
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * the speed change operation may change the
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * xmit handler, and we want to make sure
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * the next packet get through the proper
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * Tx path, so block the Tx queue until
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * the speed change has been done.
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * Jean II */
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->trans_start = jiffies;
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock_irqrestore(&self->lock, flags);
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_kfree_skb(skb);
14756ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy			return NETDEV_TX_OK;
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Change speed after current frame */
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			self->new_speed = speed;
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save current bank */
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bank = inb(iobase+BSR);
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Register and copy this frame to DMA memory */
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail;
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_fifo.queue[self->tx_fifo.free].len = skb->len;
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_fifo.tail += skb->len;
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1490af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger	dev->stats.tx_bytes += skb->len;
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1492d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo	skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start,
1493d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo		      skb->len);
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_fifo.len++;
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_fifo.free++;
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Start transmit only if there is currently no transmit going on */
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (self->tx_fifo.len == 1) {
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check if we must wait the min turn time or not */
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mtt = irda_get_mtt(skb);
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (mtt) {
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Check how much time we have used already */
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_gettimeofday(&self->now);
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			diff = self->now.tv_usec - self->stamp.tv_usec;
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (diff < 0)
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				diff += 1000000;
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Check if the mtt is larger than the time we have
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * already used by all the protocol processing
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (mtt > diff) {
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mtt -= diff;
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * Use timer if delay larger than 125 us, and
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * use udelay for smaller values which should
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * be acceptable
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (mtt > 125) {
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* Adjust for timer resolution */
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mtt = mtt / 125;
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* Setup timer */
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					switch_bank(iobase, BANK4);
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					outb(mtt & 0xff, iobase+TMRL);
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					outb((mtt >> 8) & 0x0f, iobase+TMRH);
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* Start timer */
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					outb(IRCR1_TMR_EN, iobase+IRCR1);
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					self->io.direction = IO_XMIT;
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* Enable timer interrupt */
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					switch_bank(iobase, BANK0);
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					outb(IER_TMR_IE, iobase+IER);
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* Timer will take care of the rest */
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto out;
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					udelay(mtt);
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Enable DMA interrupt */
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch_bank(iobase, BANK0);
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(IER_DMA_IE, iobase+IER);
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Transmit frame */
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nsc_ircc_dma_xmit(self, iobase);
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Not busy transmitting anymore if window is not full,
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * and if we don't need to change speed */
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((self->tx_fifo.free < MAX_TX_WINDOW) && (self->new_speed == 0))
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_wake_queue(self->netdev);
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore bank register */
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bank, iobase+BSR);
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->trans_start = jiffies;
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&self->lock, flags);
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_kfree_skb(skb);
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15626ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy	return NETDEV_TX_OK;
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_dma_xmit (self, iobase)
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Transmit data using DMA
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase)
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bsr;
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save current bank */
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bsr = inb(iobase+BSR);
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Disable DMA */
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->io.direction = IO_XMIT;
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Choose transmit DMA channel  */
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK2);
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(ECR1_DMASWP|ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1);
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irda_setup_dma(self->io.dma,
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ((u8 *)self->tx_fifo.queue[self->tx_fifo.ptr].start -
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			self->tx_buff.head) + self->tx_buff_dma,
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       self->tx_fifo.queue[self->tx_fifo.ptr].len,
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       DMA_TX_MODE);
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Enable DMA and SIR interaction pulse */
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 	switch_bank(iobase, BANK0);
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(inb(iobase+MCR)|MCR_TX_DFR|MCR_DMA_EN|MCR_IR_PLS, iobase+MCR);
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore bank register */
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bsr, iobase+BSR);
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_pio_xmit (self, iobase)
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Transmit data using PIO. Returns the number of bytes that actually
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    got transferred
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int actual = 0;
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 bank;
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1614a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	IRDA_DEBUG(4, "%s()\n", __func__);
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save current bank */
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bank = inb(iobase+BSR);
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(inb_p(iobase+LSR) & LSR_TXEMP)) {
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(4, "%s(), warning, FIFO not empty yet!\n",
1622a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			   __func__);
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIFO may still be filled to the Tx interrupt threshold */
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fifo_size -= 17;
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Fill FIFO with current frame */
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((fifo_size-- > 0) && (actual < len)) {
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Transmit next byte */
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(buf[actual++], iobase+TXD);
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_DEBUG(4, "%s(), fifo_size %d ; %d sent of %d\n",
1635a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison		   __func__, fifo_size, actual, len);
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore bank */
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bank, iobase+BSR);
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return actual;
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_dma_xmit_complete (self)
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    The transfer of a frame in finished. This function will only be called
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    by the interrupt handler
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self)
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int iobase;
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 bank;
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = TRUE;
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1656a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	IRDA_DEBUG(2, "%s()\n", __func__);
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iobase = self->io.fir_base;
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save current bank */
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bank = inb(iobase+BSR);
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Disable DMA */
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
166742b2aa86c6670347a2a07e6d7af0e0ecc8fdbff9Justin P. Mattock	/* Check for underrun! */
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inb(iobase+ASCR) & ASCR_TXUR) {
1669af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger		self->netdev->stats.tx_errors++;
1670af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger		self->netdev->stats.tx_fifo_errors++;
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Clear bit, by writing 1 into it */
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(ASCR_TXUR, iobase+ASCR);
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1675af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger		self->netdev->stats.tx_packets++;
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Finished with this frame, so prepare for next */
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_fifo.ptr++;
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_fifo.len--;
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Any frames to be sent back-to-back? */
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (self->tx_fifo.len) {
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nsc_ircc_dma_xmit(self, iobase);
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Not finished yet! */
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = FALSE;
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Reset Tx FIFO info */
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->tx_fifo.tail = self->tx_buff.head;
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make sure we have room for more frames and
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * that we don't need to change speed */
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((self->tx_fifo.free < MAX_TX_WINDOW) && (self->new_speed == 0)) {
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Not busy transmitting anymore */
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Tell the network layer, that we can accept more frames */
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_wake_queue(self->netdev);
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore bank */
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bank, iobase+BSR);
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_dma_receive (self)
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Get ready for receiving a frame. The device will initiate a DMA
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    if it starts to receive a frame.
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_dma_receive(struct nsc_ircc_cb *self)
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int iobase;
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 bsr;
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iobase = self->io.fir_base;
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reset Tx FIFO info */
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->tx_fifo.tail = self->tx_buff.head;
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save current bank */
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bsr = inb(iobase+BSR);
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Disable DMA */
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Choose DMA Rx, DMA Fairness, and Advanced mode */
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK2);
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1);
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->io.direction = IO_RECV;
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->rx_buff.data = self->rx_buff.head;
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reset Rx FIFO. This will also flush the ST_FIFO */
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->st_fifo.len = self->st_fifo.pending_bytes = 0;
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->st_fifo.tail = self->st_fifo.head = 0;
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize,
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       DMA_RX_MODE);
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Enable DMA */
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR);
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore bank register */
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bsr, iobase+BSR);
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_dma_receive_complete (self)
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Finished with receiving frames
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase)
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct st_fifo *st_fifo;
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 status;
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 bank;
17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st_fifo = &self->st_fifo;
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save current bank */
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bank = inb(iobase+BSR);
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read all entries in status FIFO */
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK5);
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) {
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We must empty the status FIFO no matter what */
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8);
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (st_fifo->tail >= MAX_RX_WINDOW) {
1787a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			IRDA_DEBUG(0, "%s(), window is full!\n", __func__);
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st_fifo->entries[st_fifo->tail].status = status;
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st_fifo->entries[st_fifo->tail].len = len;
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st_fifo->pending_bytes += len;
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st_fifo->tail++;
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st_fifo->len++;
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Try to process all entries in status FIFO */
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (st_fifo->len > 0) {
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Get first entry */
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = st_fifo->entries[st_fifo->head].status;
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len    = st_fifo->entries[st_fifo->head].len;
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st_fifo->pending_bytes -= len;
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st_fifo->head++;
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st_fifo->len--;
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check for errors */
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & FRM_ST_ERR_MSK) {
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & FRM_ST_LOST_FR) {
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Add number of lost frames to stats */
1810af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger				self->netdev->stats.rx_errors += len;
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Skip frame */
1813af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger				self->netdev->stats.rx_errors++;
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				self->rx_buff.data += len;
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & FRM_ST_MAX_LEN)
1818af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger					self->netdev->stats.rx_length_errors++;
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & FRM_ST_PHY_ERR)
1821af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger					self->netdev->stats.rx_frame_errors++;
18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & FRM_ST_BAD_CRC)
1824af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger					self->netdev->stats.rx_crc_errors++;
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* The errors below can be reported in both cases */
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & FRM_ST_OVR1)
1828af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger				self->netdev->stats.rx_fifo_errors++;
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & FRM_ST_OVR2)
1831af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger				self->netdev->stats.rx_fifo_errors++;
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * First we must make sure that the frame we
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * want to deliver is all in main memory. If we
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * cannot tell, then we check if the Rx FIFO is
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * empty. If not then we will have to take a nap
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * and try again later.
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (st_fifo->pending_bytes < self->io.fifo_size) {
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				switch_bank(iobase, BANK0);
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (inb(iobase+LSR) & LSR_RXDA) {
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* Put this entry back in fifo */
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					st_fifo->head--;
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					st_fifo->len++;
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					st_fifo->pending_bytes += len;
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					st_fifo->entries[st_fifo->head].status = status;
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					st_fifo->entries[st_fifo->head].len = len;
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/*
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 * DMA not finished yet, so try again
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 * later, set timer value, resolution
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 * 125 us
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 */
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					switch_bank(iobase, BANK4);
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					outb(0x02, iobase+TMRL); /* x 125 us */
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					outb(0x00, iobase+TMRH);
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* Start timer */
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					outb(IRCR1_TMR_EN, iobase+IRCR1);
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* Restore bank register */
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					outb(bank, iobase+BSR);
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return FALSE; /* I'll be back! */
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Remember the time we received this frame, so we can
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * reduce the min turn time a bit since we will know
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * how much time we have used for protocol processing
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_gettimeofday(&self->stamp);
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb = dev_alloc_skb(len+1);
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (skb == NULL)  {
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				IRDA_WARNING("%s(), memory squeeze, "
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     "dropping frame.\n",
1879a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison					     __func__);
1880af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger				self->netdev->stats.rx_dropped++;
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Restore bank register */
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb(bank, iobase+BSR);
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return FALSE;
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Make sure IP header gets aligned */
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb_reserve(skb, 1);
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Copy frame without CRC */
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (self->io.speed < 4000000) {
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_put(skb, len-2);
189427d7ff46a3498d3debc6ba68fb8014c702b81170Arnaldo Carvalho de Melo				skb_copy_to_linear_data(skb,
189527d7ff46a3498d3debc6ba68fb8014c702b81170Arnaldo Carvalho de Melo							self->rx_buff.data,
189627d7ff46a3498d3debc6ba68fb8014c702b81170Arnaldo Carvalho de Melo							len - 2);
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_put(skb, len-4);
189927d7ff46a3498d3debc6ba68fb8014c702b81170Arnaldo Carvalho de Melo				skb_copy_to_linear_data(skb,
190027d7ff46a3498d3debc6ba68fb8014c702b81170Arnaldo Carvalho de Melo							self->rx_buff.data,
190127d7ff46a3498d3debc6ba68fb8014c702b81170Arnaldo Carvalho de Melo							len - 4);
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Move to next frame */
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			self->rx_buff.data += len;
1906af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger			self->netdev->stats.rx_bytes += len;
1907af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger			self->netdev->stats.rx_packets++;
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb->dev = self->netdev;
1910459a98ed881802dee55897441bc7f77af614368eArnaldo Carvalho de Melo			skb_reset_mac_header(skb);
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb->protocol = htons(ETH_P_IRDA);
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			netif_rx(skb);
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore bank register */
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bank, iobase+BSR);
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return TRUE;
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_pio_receive (self)
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Receive all data in receiver FIFO
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nsc_ircc_pio_receive(struct nsc_ircc_cb *self)
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 byte;
19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int iobase;
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iobase = self->io.fir_base;
19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*  Receive all characters in Rx FIFO */
19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		byte = inb(iobase+RXD);
1937af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger		async_unwrap_char(self->netdev, &self->netdev->stats,
1938af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger				  &self->rx_buff, byte);
19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (inb(iobase+LSR) & LSR_RXDA); /* Data available */
19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_sir_interrupt (self, eir)
19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Handle SIR interrupt
19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir)
19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int actual;
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check if transmit FIFO is low on data */
19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (eir & EIR_TXLDL_EV) {
19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Write data left in transmit buffer */
19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		actual = nsc_ircc_pio_write(self->io.fir_base,
19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   self->tx_buff.data,
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   self->tx_buff.len,
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   self->io.fifo_size);
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->tx_buff.data += actual;
19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->tx_buff.len  -= actual;
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->io.direction = IO_XMIT;
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check if finished */
19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (self->tx_buff.len > 0)
19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			self->ier = IER_TXLDL_IE;
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1969af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger			self->netdev->stats.tx_packets++;
19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			netif_wake_queue(self->netdev);
19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			self->ier = IER_TXEMP_IE;
19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check if transmission has completed */
19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (eir & EIR_TXEMP_EV) {
19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Turn around and get ready to receive some data */
19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->io.direction = IO_RECV;
19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->ier = IER_RXHDL_IE;
19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check if we need to change the speed?
19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Need to be after self->io.direction to avoid race with
19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * nsc_ircc_hard_xmit_sir() - Jean II */
19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (self->new_speed) {
1984a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison			IRDA_DEBUG(2, "%s(), Changing speed!\n", __func__);
19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			self->ier = nsc_ircc_change_speed(self,
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  self->new_speed);
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			self->new_speed = 0;
19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			netif_wake_queue(self->netdev);
19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Check if we are going to FIR */
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (self->io.speed > 115200) {
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* No need to do anymore SIR stuff */
19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return;
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Rx FIFO threshold or timeout */
19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (eir & EIR_RXHDL_EV) {
20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nsc_ircc_pio_receive(self);
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Keep receiving */
20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->ier = IER_RXHDL_IE;
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_fir_interrupt (self, eir)
20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Handle MIR/FIR interrupt
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase,
20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   int eir)
20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 bank;
20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bank = inb(iobase+BSR);
20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Status FIFO event*/
20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (eir & EIR_SFIF_EV) {
20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check if DMA has finished */
20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (nsc_ircc_dma_receive_complete(self, iobase)) {
20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Wait for next status FIFO interrupt */
20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			self->ier = IER_SFIF_IE;
20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			self->ier = IER_SFIF_IE | IER_TMR_IE;
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (eir & EIR_TMR_EV) { /* Timer finished */
20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Disable timer */
20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch_bank(iobase, BANK4);
20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0, iobase+IRCR1);
20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Clear timer event */
20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch_bank(iobase, BANK0);
20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(ASCR_CTE, iobase+ASCR);
20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check if this is a Tx timer interrupt */
20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (self->io.direction == IO_XMIT) {
20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nsc_ircc_dma_xmit(self, iobase);
20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Interrupt on DMA */
20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			self->ier = IER_DMA_IE;
20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Check (again) if DMA has finished */
20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (nsc_ircc_dma_receive_complete(self, iobase)) {
20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				self->ier = IER_SFIF_IE;
20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				self->ier = IER_SFIF_IE | IER_TMR_IE;
20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (eir & EIR_DMA_EV) {
20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Finished with all transmissions? */
20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (nsc_ircc_dma_xmit_complete(self)) {
20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(self->new_speed != 0) {
20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* As we stop the Tx queue, the speed change
20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * need to be done when the Tx fifo is
20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * empty. Ask for a Tx done interrupt */
20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				self->ier = IER_TXEMP_IE;
20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Check if there are more frames to be
20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * transmitted */
20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (irda_device_txqueue_empty(self->netdev)) {
20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* Prepare for receive */
20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					nsc_ircc_dma_receive(self);
20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					self->ier = IER_SFIF_IE;
20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else
20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					IRDA_WARNING("%s(), potential "
20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						     "Tx queue lockup !\n",
2070a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison						     __func__);
20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*  Not finished yet, so interrupt on DMA again */
20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			self->ier = IER_DMA_IE;
20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (eir & EIR_TXEMP_EV) {
20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* The Tx FIFO has totally drained out, so now we can change
20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the speed... - Jean II */
20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->ier = nsc_ircc_change_speed(self, self->new_speed);
20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->new_speed = 0;
20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_wake_queue(self->netdev);
20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Note : nsc_ircc_change_speed() restarted Rx fifo */
20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bank, iobase+BSR);
20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_interrupt (irq, dev_id, regs)
20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    An interrupt from the chip has arrived. Time to do some work
20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
20947d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t nsc_ircc_interrupt(int irq, void *dev_id)
20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2096c31f28e778ab299a5035ea2bda64f245b8915d7cJeff Garzik	struct net_device *dev = dev_id;
20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nsc_ircc_cb *self;
20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 bsr, eir;
20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int iobase;
21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21014cf1653aa90c6320dc8032443b5e322820aa28b1Wang Chen	self = netdev_priv(dev);
21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&self->lock);
21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iobase = self->io.fir_base;
21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bsr = inb(iobase+BSR); 	/* Save current bank */
21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->ier = inb(iobase+IER);
21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	eir = inb(iobase+EIR) & self->ier; /* Mask out the interesting ones */
21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, iobase+IER); /* Disable interrupts */
21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (eir) {
21161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Dispatch interrupt handler for the current speed */
21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (self->io.speed > 115200)
21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nsc_ircc_fir_interrupt(self, iobase, eir);
21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nsc_ircc_sir_interrupt(self, eir);
21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(self->ier, iobase+IER); /* Restore interrupts */
21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bsr, iobase+BSR);       /* Restore bank register */
21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&self->lock);
21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_RETVAL(eir);
21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_is_receiving (self)
21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Return TRUE is we are currently receiving a frame
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_is_receiving(struct nsc_ircc_cb *self)
21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int status = FALSE;
21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int iobase;
21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 bank;
21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self != NULL, return FALSE;);
21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&self->lock, flags);
21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (self->io.speed > 115200) {
21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iobase = self->io.fir_base;
21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check if rx FIFO is not empty */
21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bank = inb(iobase+BSR);
21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch_bank(iobase, BANK2);
21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((inb(iobase+RXFLV) & 0x3f) != 0) {
21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* We are receiving something */
21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			status =  TRUE;
21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(bank, iobase+BSR);
21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = (self->rx_buff.state != OUTSIDE_FRAME);
21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&self->lock, flags);
21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return status;
21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_net_open (dev)
21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Start the device
21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_net_open(struct net_device *dev)
21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nsc_ircc_cb *self;
21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int iobase;
21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char hwname[32];
21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 bank;
21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2179a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	IRDA_DEBUG(4, "%s()\n", __func__);
21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(dev != NULL, return -1;);
21824cf1653aa90c6320dc8032443b5e322820aa28b1Wang Chen	self = netdev_priv(dev);
21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self != NULL, return 0;);
21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iobase = self->io.fir_base;
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, dev->name, dev)) {
21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_WARNING("%s, unable to allocate irq=%d\n",
21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     driver_name, self->io.irq);
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Always allocate the DMA channel after the IRQ, and clean up on
21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * failure.
21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (request_dma(self->io.dma, dev->name)) {
21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_WARNING("%s, unable to allocate dma=%d\n",
21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     driver_name, self->io.dma);
22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_irq(self->io.irq, dev);
22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save current bank */
22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bank = inb(iobase+BSR);
22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn on interrupts */
22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(IER_LS_IE | IER_RXHDL_IE, iobase+IER);
22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore bank register */
22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bank, iobase+BSR);
22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Ready to play! */
22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_start_queue(dev);
22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Give self a hardware name */
22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sprintf(hwname, "NSC-FIR @ 0x%03x", self->io.fir_base);
22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Open new IrLAP layer instance, now that everything should be
22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * initialized properly
22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->irlap = irlap_open(dev, &self->qos, hwname);
22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_net_close (dev)
22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Stop the device
22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_net_close(struct net_device *dev)
22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nsc_ircc_cb *self;
22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int iobase;
22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 bank;
22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2241a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	IRDA_DEBUG(4, "%s()\n", __func__);
22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(dev != NULL, return -1;);
22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22454cf1653aa90c6320dc8032443b5e322820aa28b1Wang Chen	self = netdev_priv(dev);
22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self != NULL, return 0;);
22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Stop device */
22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Stop and remove instance of IrLAP */
22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (self->irlap)
22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irlap_close(self->irlap);
22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->irlap = NULL;
22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iobase = self->io.fir_base;
22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	disable_dma(self->io.dma);
22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save current bank */
22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bank = inb(iobase+BSR);
22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Disable interrupts */
22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_bank(iobase, BANK0);
22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, iobase+IER);
22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(self->io.irq, dev);
22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_dma(self->io.dma);
22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore bank register */
22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(bank, iobase+BSR);
22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function nsc_ircc_net_ioctl (dev, rq, cmd)
22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Process IOCTL commands for this device
22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct if_irda_req *irq = (struct if_irda_req *) rq;
22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nsc_ircc_cb *self;
22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(dev != NULL, return -1;);
22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22914cf1653aa90c6320dc8032443b5e322820aa28b1Wang Chen	self = netdev_priv(dev);
22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self != NULL, return -1;);
22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2295a97a6f10771b90235b33c13a6db9279237a08422Harvey Harrison	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SIOCSBANDWIDTH: /* Set bandwidth */
22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!capable(CAP_NET_ADMIN)) {
23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = -EPERM;
23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irqsave(&self->lock, flags);
23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nsc_ircc_change_speed(self, irq->ifr_baudrate);
23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&self->lock, flags);
23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SIOCSMEDIABUSY: /* Set media busy */
23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!capable(CAP_NET_ADMIN)) {
23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = -EPERM;
23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irda_device_set_media_busy(self->netdev, TRUE);
23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SIOCGRECEIVING: /* Check if we are receiving right now */
23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* This is already protected */
23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq->ifr_receiving = nsc_ircc_is_receiving(self);
23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EOPNOTSUPP;
23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23243b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhovstatic int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state)
23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23263b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov     	struct nsc_ircc_cb *self = platform_get_drvdata(dev);
23273b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov 	int bank;
23283b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	unsigned long flags;
23293b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov 	int iobase = self->io.fir_base;
23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (self->io.suspended)
23323b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		return 0;
23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23343b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	IRDA_DEBUG(1, "%s, Suspending\n", driver_name);
23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23363b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	rtnl_lock();
23373b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	if (netif_running(self->netdev)) {
23383b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		netif_device_detach(self->netdev);
23393b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		spin_lock_irqsave(&self->lock, flags);
23403b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		/* Save current bank */
23413b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		bank = inb(iobase+BSR);
23423b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov
23433b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		/* Disable interrupts */
23443b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		switch_bank(iobase, BANK0);
23453b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		outb(0, iobase+IER);
23463b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov
23473b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		/* Restore bank register */
23483b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		outb(bank, iobase+BSR);
23493b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov
23503b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		spin_unlock_irqrestore(&self->lock, flags);
23513b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		free_irq(self->io.irq, self->netdev);
23523b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		disable_dma(self->io.dma);
23533b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	}
23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->io.suspended = 1;
23553b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	rtnl_unlock();
23563b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov
23573b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	return 0;
23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23603b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhovstatic int nsc_ircc_resume(struct platform_device *dev)
23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23623b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov 	struct nsc_ircc_cb *self = platform_get_drvdata(dev);
23633b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov 	unsigned long flags;
23643b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov
23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!self->io.suspended)
23663b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		return 0;
23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23683b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	IRDA_DEBUG(1, "%s, Waking up\n", driver_name);
23693b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov
23703b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	rtnl_lock();
23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nsc_ircc_setup(&self->io);
23723b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	nsc_ircc_init_dongle_interface(self->io.fir_base, self->io.dongle_id);
23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23743b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	if (netif_running(self->netdev)) {
23753b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		if (request_irq(self->io.irq, nsc_ircc_interrupt, 0,
23763b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov				self->netdev->name, self->netdev)) {
23773b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov 		    	IRDA_WARNING("%s, unable to allocate irq=%d\n",
23783b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov				     driver_name, self->io.irq);
23793b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov
23803b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov			/*
23813b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov			 * Don't fail resume process, just kill this
23823b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov			 * network interface
23833b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov			 */
23843b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov			unregister_netdevice(self->netdev);
23853b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		} else {
23863b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov			spin_lock_irqsave(&self->lock, flags);
23873b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov			nsc_ircc_change_speed(self, self->io.speed);
23883b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov			spin_unlock_irqrestore(&self->lock, flags);
23893b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov			netif_device_attach(self->netdev);
23903b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		}
23913b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov
23923b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	} else {
23933b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		spin_lock_irqsave(&self->lock, flags);
23943b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		nsc_ircc_change_speed(self, 9600);
23953b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov		spin_unlock_irqrestore(&self->lock, flags);
23963b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	}
23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	self->io.suspended = 0;
23983b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov	rtnl_unlock();
23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24003b99b93baba4cbf4fd3d206e65e81a070b21b560Dmitry Torokhov 	return 0;
24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("NSC IrDA Device Driver");
24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(qos_mtt_bits, int, 0);
24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(io, int, NULL, 0);
24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(io, "Base I/O addresses");
24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(irq, int, NULL, 0);
24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(irq, "IRQ lines");
24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(dma, int, NULL, 0);
24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(dma, "DMA channels");
24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(dongle_id, int, 0);
24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(dongle_id, "Type-id of used dongle");
24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(nsc_ircc_init);
24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(nsc_ircc_cleanup);
24211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2422