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