1c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/***************************************************************************** 2c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* 3c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Filename: mcs7780.c 4c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Version: 0.4-alpha 5c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Description: Irda MosChip USB Dongle Driver 6c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Authors: Lukasz Stelmach <stlman@poczta.fm> 7c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Brian Pugh <bpugh@cs.pdx.edu> 8c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Judy Fischbach <jfisch@cs.pdx.edu> 9c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* 10c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Based on stir4200 driver, but some things done differently. 11c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Based on earlier driver by Paul Stewart <stewart@parc.com> 12c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* 13c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at> 14c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Copyright (C) 2001, Dag Brattli <dag@brattli.net> 15c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> 16c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org> 17c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Copyright (C) 2005, Lukasz Stelmach <stlman@poczta.fm> 18c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Copyright (C) 2005, Brian Pugh <bpugh@cs.pdx.edu> 19c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Copyright (C) 2005, Judy Fischbach <jfisch@cs.pdx.edu> 20c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* 21c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* This program is free software; you can redistribute it and/or modify 22c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* it under the terms of the GNU General Public License as published by 23c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* the Free Software Foundation; either version 2 of the License, or 24c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* (at your option) any later version. 25c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* 26c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* This program is distributed in the hope that it will be useful, 27c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* but WITHOUT ANY WARRANTY; without even the implied warranty of 28c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* GNU General Public License for more details. 30c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* 31c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* You should have received a copy of the GNU General Public License 32c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* along with this program; if not, write to the Free Software 33c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 34c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz* 35c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz*****************************************************************************/ 36c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 37c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* 38c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * MCS7780 is a simple USB to IrDA bridge by MosChip. It is neither 39c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * compatibile with irda-usb nor with stir4200. Although it is quite 40c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * similar to the later as far as general idea of operation is concerned. 41c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * That is it requires the software to do all the framing job at SIR speeds. 42c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * The hardware does take care of the framing at MIR and FIR speeds. 43c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * It supports all speeds from 2400 through 4Mbps 44c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 45c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 46c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <linux/module.h> 47c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <linux/moduleparam.h> 48c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <linux/kernel.h> 49c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <linux/types.h> 50c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <linux/errno.h> 51c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <linux/init.h> 52c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <linux/slab.h> 53c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <linux/usb.h> 54c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <linux/device.h> 55c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <linux/crc32.h> 56c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 57c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <asm/unaligned.h> 58c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <asm/byteorder.h> 59c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <asm/uaccess.h> 60c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 61c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <net/irda/irda.h> 62c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <net/irda/wrapper.h> 63c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include <net/irda/crc.h> 64c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 65c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#include "mcs7780.h" 66c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 67c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#define MCS_VENDOR_ID 0x9710 68c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz#define MCS_PRODUCT_ID 0x7780 69c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 70c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic struct usb_device_id mcs_table[] = { 71c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* MosChip Corp., MCS7780 FIR-USB Adapter */ 72c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz {USB_DEVICE(MCS_VENDOR_ID, MCS_PRODUCT_ID)}, 73c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz {}, 74c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz}; 75c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 76c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel OrtizMODULE_AUTHOR("Brian Pugh <bpugh@cs.pdx.edu>"); 77c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel OrtizMODULE_DESCRIPTION("IrDA-USB Dongle Driver for MosChip MCS7780"); 78c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel OrtizMODULE_VERSION("0.3alpha"); 79c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel OrtizMODULE_LICENSE("GPL"); 80c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 81c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel OrtizMODULE_DEVICE_TABLE(usb, mcs_table); 82c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 83c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic int qos_mtt_bits = 0x07 /* > 1ms */ ; 84c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizmodule_param(qos_mtt_bits, int, 0); 85c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel OrtizMODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); 86c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 87c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic int receive_mode = 0x1; 88c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizmodule_param(receive_mode, int, 0); 89c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel OrtizMODULE_PARM_DESC(receive_mode, 90c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz "Receive mode of the device (1:fast, 0:slow, default:1)"); 91c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 92c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic int sir_tweak = 1; 93c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizmodule_param(sir_tweak, int, 0444); 94c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel OrtizMODULE_PARM_DESC(sir_tweak, 95c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz "Default pulse width (1:1.6us, 0:3/16 bit, default:1)."); 96c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 97c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic int transceiver_type = MCS_TSC_VISHAY; 98c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizmodule_param(transceiver_type, int, 0444); 99c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel OrtizMODULE_PARM_DESC(transceiver_type, "IR transceiver type, see mcs7780.h."); 100c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 1017263ade1e1e72e34fc3c179f3aeaa07a11872d22Adrian Bunkstatic struct usb_driver mcs_driver = { 102c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz .name = "mcs7780", 103c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz .probe = mcs_probe, 104c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz .disconnect = mcs_disconnect, 105c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz .id_table = mcs_table, 106c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz}; 107c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 108c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* speed flag selection by direct addressing. 109c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizaddr = (speed >> 8) & 0x0f 110c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 111c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz0x1 57600 0x2 115200 0x4 1152000 0x5 9600 112c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz0x6 38400 0x9 2400 0xa 576000 0xb 19200 113c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 114c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz4Mbps (or 2400) must be checked separately. Since it also has 115c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizto be programmed in a different manner that is not a big problem. 116c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz*/ 117c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic __u16 mcs_speed_set[16] = { 0, 118c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz MCS_SPEED_57600, 119c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz MCS_SPEED_115200, 120c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 0, 121c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz MCS_SPEED_1152000, 122c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz MCS_SPEED_9600, 123c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz MCS_SPEED_38400, 124c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 0, 0, 125c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz MCS_SPEED_2400, 126c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz MCS_SPEED_576000, 127c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz MCS_SPEED_19200, 128c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 0, 0, 0, 129c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz}; 130c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 131c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Set given 16 bit register with a 16 bit value. Send control message 132c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * to set dongle register. */ 133c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic int mcs_set_reg(struct mcs_cb *mcs, __u16 reg, __u16 val) 134c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 135c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct usb_device *dev = mcs->usbdev; 136c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, 137c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz MCS_WR_RTYPE, val, reg, NULL, 0, 138c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz msecs_to_jiffies(MCS_CTRL_TIMEOUT)); 139c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 140c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 141c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Get 16 bit register value. Send contol message to read dongle register. */ 142c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val) 143c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 144c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct usb_device *dev = mcs->usbdev; 145c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, 146c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz MCS_RD_RTYPE, 0, reg, val, 2, 147c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz msecs_to_jiffies(MCS_CTRL_TIMEOUT)); 148c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 149c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return ret; 150c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 151c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 152c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Setup a communication between mcs7780 and TFDU chips. It is described 153c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * in more detail in the data sheet. The setup sequence puts the the 154c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * vishay tranceiver into high speed mode. It will also receive SIR speed 155c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * packets but at reduced sensitivity. 156c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 157c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 158c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* 0: OK 1:ERROR */ 159c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic inline int mcs_setup_transceiver_vishay(struct mcs_cb *mcs) 160c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 161c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int ret = 0; 162c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz __u16 rval; 163c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 164c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* mcs_get_reg should read exactly two bytes from the dongle */ 165c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_get_reg(mcs, MCS_XCVR_REG, &rval); 166c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (unlikely(ret != 2)) { 167c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = -EIO; 168c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 169c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 170c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 171c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* The MCS_XCVR_CONF bit puts the transceiver into configuration 172c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * mode. The MCS_MODE0 bit must start out high (1) and then 173c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * transition to low and the MCS_STFIR and MCS_MODE1 bits must 174c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * be low. 175c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 176c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval |= (MCS_MODE0 | MCS_XCVR_CONF); 177c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~MCS_STFIR; 178c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~MCS_MODE1; 179c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval); 180c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (unlikely(ret)) 181c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 182c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 183c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~MCS_MODE0; 184c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval); 185c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (unlikely(ret)) 186c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 187c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 188c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~MCS_XCVR_CONF; 189c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval); 190c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (unlikely(ret)) 191c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 192c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 193c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = 0; 194c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz error: 195c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return ret; 196c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 197c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 198c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Setup a communication between mcs7780 and agilent chip. */ 199c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic inline int mcs_setup_transceiver_agilent(struct mcs_cb *mcs) 200c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 201599b1fa91439cff8605a71f1a2b5bb42c177b667Samuel Ortiz IRDA_WARNING("This transceiver type is not supported yet.\n"); 202c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return 1; 203c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 204c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 205c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Setup a communication between mcs7780 and sharp chip. */ 206c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic inline int mcs_setup_transceiver_sharp(struct mcs_cb *mcs) 207c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 208599b1fa91439cff8605a71f1a2b5bb42c177b667Samuel Ortiz IRDA_WARNING("This transceiver type is not supported yet.\n"); 209c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return 1; 210c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 211c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 212c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Common setup for all transceivers */ 213c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic inline int mcs_setup_transceiver(struct mcs_cb *mcs) 214c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 215c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int ret = 0; 216c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz __u16 rval; 217c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz char *msg; 218c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 219c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz msg = "Basic transceiver setup error."; 220c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 221c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* read value of MODE Register, set the DRIVER and RESET bits 222c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * and write value back out to MODE Register 223c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 224c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval); 225c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if(unlikely(ret != 2)) 226c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 227c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval |= MCS_DRIVER; /* put the mcs7780 into configuration mode. */ 228c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); 229c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if(unlikely(ret)) 230c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 231c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 232c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval = 0; /* set min pulse width to 0 initially. */ 233c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_set_reg(mcs, MCS_MINRXPW_REG, rval); 234c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if(unlikely(ret)) 235c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 236c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 237c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval); 238c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if(unlikely(ret != 2)) 239c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 240c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 241c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~MCS_FIR; /* turn off fir mode. */ 242c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if(mcs->sir_tweak) 243c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval |= MCS_SIR16US; /* 1.6us pulse width */ 244c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz else 245c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~MCS_SIR16US; /* 3/16 bit time pulse width */ 246c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 247c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* make sure ask mode and back to back packets are off. */ 248c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~(MCS_BBTG | MCS_ASK); 249c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 250c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~MCS_SPEED_MASK; 251c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval |= MCS_SPEED_9600; /* make sure initial speed is 9600. */ 252c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->speed = 9600; 253c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->new_speed = 0; /* new_speed is set to 0 */ 254c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~MCS_PLLPWDN; /* disable power down. */ 255c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 256c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* make sure device determines direction and that the auto send sip 257c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * pulse are on. 258c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 259c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval |= MCS_DTD | MCS_SIPEN; 260c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 261c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); 262c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if(unlikely(ret)) 263c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 264c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 265c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz msg = "transceiver model specific setup error."; 266c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz switch (mcs->transceiver_type) { 267c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz case MCS_TSC_VISHAY: 268c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_setup_transceiver_vishay(mcs); 269c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz break; 270c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 271c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz case MCS_TSC_SHARP: 272c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_setup_transceiver_sharp(mcs); 273c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz break; 274c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 275c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz case MCS_TSC_AGILENT: 276c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_setup_transceiver_agilent(mcs); 277c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz break; 278c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 279c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz default: 280599b1fa91439cff8605a71f1a2b5bb42c177b667Samuel Ortiz IRDA_WARNING("Unknown transceiver type: %d\n", 281c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->transceiver_type); 282c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = 1; 283c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 284c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (unlikely(ret)) 285c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 286c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 287c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* If transceiver is not SHARP, then if receive mode set 288c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * on the RXFAST bit in the XCVR Register otherwise unset it 289c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 290c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (mcs->transceiver_type != MCS_TSC_SHARP) { 291c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 292c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_get_reg(mcs, MCS_XCVR_REG, &rval); 293c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (unlikely(ret != 2)) 294c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 295c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (mcs->receive_mode) 296c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval |= MCS_RXFAST; 297c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz else 298c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~MCS_RXFAST; 299c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval); 300c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (unlikely(ret)) 301c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 302c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 303c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 304c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz msg = "transceiver reset."; 305c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 306c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval); 307c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (unlikely(ret != 2)) 308c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 309c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 310c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* reset the mcs7780 so all changes take effect. */ 311c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~MCS_RESET; 312c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); 313c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (unlikely(ret)) 314c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 315c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz else 316c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return ret; 317c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 318c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizerror: 319599b1fa91439cff8605a71f1a2b5bb42c177b667Samuel Ortiz IRDA_ERROR("%s\n", msg); 320c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return ret; 321c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 322c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 323c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Wraps the data in format for SIR */ 324c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic inline int mcs_wrap_sir_skb(struct sk_buff *skb, __u8 * buf) 325c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 326c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int wraplen; 327c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 328c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* 2: full frame length, including "the length" */ 329c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz wraplen = async_wrap_skb(skb, buf + 2, 4094); 330c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 331c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz wraplen += 2; 332c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz buf[0] = wraplen & 0xff; 333c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz buf[1] = (wraplen >> 8) & 0xff; 334c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 335c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return wraplen; 336c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 337c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 338c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Wraps the data in format for FIR */ 339c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic unsigned mcs_wrap_fir_skb(const struct sk_buff *skb, __u8 *buf) 340c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 341c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz unsigned int len = 0; 342c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz __u32 fcs = ~(crc32_le(~0, skb->data, skb->len)); 343c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 344c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* add 2 bytes for length value and 4 bytes for fcs. */ 345c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz len = skb->len + 6; 346c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 347c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* The mcs7780 requires that the first two bytes are the packet 348c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * length in little endian order. Note: the length value includes 349c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * the two bytes for the length value itself. 350c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 351c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz buf[0] = len & 0xff; 352c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz buf[1] = (len >> 8) & 0xff; 353c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* copy the data into the tx buffer. */ 354d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo skb_copy_from_linear_data(skb, buf + 2, skb->len); 355c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* put the fcs in the last four bytes in little endian order. */ 356c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz buf[len - 4] = fcs & 0xff; 357c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz buf[len - 3] = (fcs >> 8) & 0xff; 358c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz buf[len - 2] = (fcs >> 16) & 0xff; 359c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz buf[len - 1] = (fcs >> 24) & 0xff; 360c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 361c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return len; 362c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 363c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 364c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Wraps the data in format for MIR */ 365c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic unsigned mcs_wrap_mir_skb(const struct sk_buff *skb, __u8 *buf) 366c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 367c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz __u16 fcs = 0; 368c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int len = skb->len + 4; 369c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 370c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz fcs = ~(irda_calc_crc16(~fcs, skb->data, skb->len)); 371c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* put the total packet length in first. Note: packet length 372c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * value includes the two bytes that hold the packet length 373c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * itself. 374c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 375c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz buf[0] = len & 0xff; 376c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz buf[1] = (len >> 8) & 0xff; 377c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* copy the data */ 378d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo skb_copy_from_linear_data(skb, buf + 2, skb->len); 379c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* put the fcs in last two bytes in little endian order. */ 380c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz buf[len - 2] = fcs & 0xff; 381c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz buf[len - 1] = (fcs >> 8) & 0xff; 382c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 383c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return len; 384c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 385c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 386c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Unwrap received packets at MIR speed. A 16 bit crc_ccitt checksum is 387c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * used for the fcs. When performed over the entire packet the result 388c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * should be GOOD_FCS = 0xf0b8. Hands the unwrapped data off to the IrDA 389c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * layer via a sk_buff. 390c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 391c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len) 392c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 393c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz __u16 fcs; 394c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int new_len; 395c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct sk_buff *skb; 396c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 397c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* Assume that the frames are going to fill a single packet 398c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * rather than span multiple packets. 399c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 400c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 401c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz new_len = len - 2; 402c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if(unlikely(new_len <= 0)) { 403c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz IRDA_ERROR("%s short frame length %d\n", 404c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->netdev->name, new_len); 405af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger ++mcs->netdev->stats.rx_errors; 406af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger ++mcs->netdev->stats.rx_length_errors; 407c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return; 408c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 409c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz fcs = 0; 410c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz fcs = irda_calc_crc16(~fcs, buf, len); 411c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 412c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if(fcs != GOOD_FCS) { 413c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz IRDA_ERROR("crc error calc 0x%x len %d\n", 414c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz fcs, new_len); 415af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger mcs->netdev->stats.rx_errors++; 416af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger mcs->netdev->stats.rx_crc_errors++; 417c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return; 418c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 419c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 420c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz skb = dev_alloc_skb(new_len + 1); 421c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if(unlikely(!skb)) { 422af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger ++mcs->netdev->stats.rx_dropped; 423c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return; 424c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 425c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 426c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz skb_reserve(skb, 1); 42727d7ff46a3498d3debc6ba68fb8014c702b81170Arnaldo Carvalho de Melo skb_copy_to_linear_data(skb, buf, new_len); 428c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz skb_put(skb, new_len); 429459a98ed881802dee55897441bc7f77af614368eArnaldo Carvalho de Melo skb_reset_mac_header(skb); 430c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz skb->protocol = htons(ETH_P_IRDA); 431c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz skb->dev = mcs->netdev; 432c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 433c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz netif_rx(skb); 434c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 435af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger mcs->netdev->stats.rx_packets++; 436af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger mcs->netdev->stats.rx_bytes += new_len; 437c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 438c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 439c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Unwrap received packets at FIR speed. A 32 bit crc_ccitt checksum is 440c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * used for the fcs. Hands the unwrapped data off to the IrDA 441c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * layer via a sk_buff. 442c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 443c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len) 444c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 445c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz __u32 fcs; 446c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int new_len; 447c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct sk_buff *skb; 448c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 449c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* Assume that the frames are going to fill a single packet 450c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * rather than span multiple packets. This is most likely a false 451c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * assumption. 452c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 453c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 454c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz new_len = len - 4; 455c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if(unlikely(new_len <= 0)) { 456c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz IRDA_ERROR("%s short frame length %d\n", 457c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->netdev->name, new_len); 458af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger ++mcs->netdev->stats.rx_errors; 459af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger ++mcs->netdev->stats.rx_length_errors; 460c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return; 461c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 462c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 463c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz fcs = ~(crc32_le(~0, buf, new_len)); 4646caf52a453d5fe0bc584a2895bfd39a3d9054829Harvey Harrison if(fcs != get_unaligned_le32(buf + new_len)) { 465c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len); 466af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger mcs->netdev->stats.rx_errors++; 467af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger mcs->netdev->stats.rx_crc_errors++; 468c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return; 469c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 470c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 471c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz skb = dev_alloc_skb(new_len + 1); 472c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if(unlikely(!skb)) { 473af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger ++mcs->netdev->stats.rx_dropped; 474c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return; 475c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 476c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 477c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz skb_reserve(skb, 1); 47827d7ff46a3498d3debc6ba68fb8014c702b81170Arnaldo Carvalho de Melo skb_copy_to_linear_data(skb, buf, new_len); 479c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz skb_put(skb, new_len); 480459a98ed881802dee55897441bc7f77af614368eArnaldo Carvalho de Melo skb_reset_mac_header(skb); 481c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz skb->protocol = htons(ETH_P_IRDA); 482c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz skb->dev = mcs->netdev; 483c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 484c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz netif_rx(skb); 485c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 486af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger mcs->netdev->stats.rx_packets++; 487af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger mcs->netdev->stats.rx_bytes += new_len; 488c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 489c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 490c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 491c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Allocates urbs for both receive and transmit. 492c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * If alloc fails return error code 0 (fail) otherwise 493c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * return error code 1 (success). 494c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 495c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic inline int mcs_setup_urbs(struct mcs_cb *mcs) 496c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 497c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->rx_urb = NULL; 498c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 499c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->tx_urb = usb_alloc_urb(0, GFP_KERNEL); 500c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (!mcs->tx_urb) 501c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return 0; 502c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 503c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->rx_urb = usb_alloc_urb(0, GFP_KERNEL); 504c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (!mcs->rx_urb) 505c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return 0; 506c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 507c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return 1; 508c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 509c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 510c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Sets up state to be initially outside frame, gets receive urb, 511c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * sets status to successful and then submits the urb to start 512c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * receiving the data. 513c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 514c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic inline int mcs_receive_start(struct mcs_cb *mcs) 515c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 516c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->rx_buff.in_frame = FALSE; 517c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->rx_buff.state = OUTSIDE_FRAME; 518c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 519c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz usb_fill_bulk_urb(mcs->rx_urb, mcs->usbdev, 520c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz usb_rcvbulkpipe(mcs->usbdev, mcs->ep_in), 521c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->in_buf, 4096, mcs_receive_irq, mcs); 522c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 523c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->rx_urb->status = 0; 524c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return usb_submit_urb(mcs->rx_urb, GFP_KERNEL); 525c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 526c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 527c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Finds the in and out endpoints for the mcs control block */ 528c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic inline int mcs_find_endpoints(struct mcs_cb *mcs, 529c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct usb_host_endpoint *ep, int epnum) 530c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 531c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int i; 532c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int ret = 0; 533c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 534c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* If no place to store the endpoints just return */ 535c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (!ep) 536c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return ret; 537c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 538c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* cycle through all endpoints, find the first two that are DIR_IN */ 539c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz for (i = 0; i < epnum; i++) { 540c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (ep[i].desc.bEndpointAddress & USB_DIR_IN) 541c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->ep_in = ep[i].desc.bEndpointAddress; 542c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz else 543c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->ep_out = ep[i].desc.bEndpointAddress; 544c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 545c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* MosChip says that the chip has only two bulk 546c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * endpoints. Find one for each direction and move on. 547c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 548c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if ((mcs->ep_in != 0) && (mcs->ep_out != 0)) { 549c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = 1; 550c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz break; 551c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 552c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 553c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 554c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return ret; 555c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 556c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 557c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void mcs_speed_work(struct work_struct *work) 558c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 559c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells struct mcs_cb *mcs = container_of(work, struct mcs_cb, work); 560c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct net_device *netdev = mcs->netdev; 561c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 562c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs_speed_change(mcs); 563c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz netif_wake_queue(netdev); 564c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 565c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 566c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Function to change the speed of the mcs7780. Fully supports SIR, 567c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * MIR, and FIR speeds. 568c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 569c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic int mcs_speed_change(struct mcs_cb *mcs) 570c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 571c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int ret = 0; 572c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int rst = 0; 573c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int cnt = 0; 574c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz __u16 nspeed; 575c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz __u16 rval; 576c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 577c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz nspeed = mcs_speed_set[(mcs->new_speed >> 8) & 0x0f]; 578c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 579c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz do { 580c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs_get_reg(mcs, MCS_RESV_REG, &rval); 581c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } while(cnt++ < 100 && (rval & MCS_IRINTX)); 582c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 583fb0886745a75ce98bde3aac421adc69fe61a1905Roel Kluin if (cnt > 100) { 584599b1fa91439cff8605a71f1a2b5bb42c177b667Samuel Ortiz IRDA_ERROR("unable to change speed\n"); 585c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = -EIO; 586c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 587c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 588c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 589c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs_get_reg(mcs, MCS_MODE_REG, &rval); 590c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 59125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi /* MINRXPW values recommended by MosChip */ 592c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (mcs->new_speed <= 115200) { 593c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~MCS_FIR; 594c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 595c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if ((rst = (mcs->speed > 115200))) 596c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs_set_reg(mcs, MCS_MINRXPW_REG, 0); 597c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 598c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } else if (mcs->new_speed <= 1152000) { 599c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~MCS_FIR; 600c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 601c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if ((rst = !(mcs->speed == 576000 || mcs->speed == 1152000))) 602c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs_set_reg(mcs, MCS_MINRXPW_REG, 5); 603c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 604c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } else { 605c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval |= MCS_FIR; 606c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 607c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if ((rst = (mcs->speed != 4000000))) 608c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs_set_reg(mcs, MCS_MINRXPW_REG, 5); 609c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 610c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 611c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 612c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~MCS_SPEED_MASK; 613c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval |= nspeed; 614c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 615c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); 616c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (unlikely(ret)) 617c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 618c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 619c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (rst) 620c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz switch (mcs->transceiver_type) { 621c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz case MCS_TSC_VISHAY: 622c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_setup_transceiver_vishay(mcs); 623c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz break; 624c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 625c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz case MCS_TSC_SHARP: 626c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_setup_transceiver_sharp(mcs); 627c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz break; 628c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 629c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz case MCS_TSC_AGILENT: 630c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_setup_transceiver_agilent(mcs); 631c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz break; 632c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 633c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz default: 634c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = 1; 635599b1fa91439cff8605a71f1a2b5bb42c177b667Samuel Ortiz IRDA_WARNING("Unknown transceiver type: %d\n", 636c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->transceiver_type); 637c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 638c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (unlikely(ret)) 639c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error; 640c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 641c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs_get_reg(mcs, MCS_MODE_REG, &rval); 642c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz rval &= ~MCS_RESET; 643c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); 644c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 645c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->speed = mcs->new_speed; 646c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz error: 647c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->new_speed = 0; 648c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return ret; 649c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 650c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 651c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Ioctl calls not supported at this time. Can be an area of future work. */ 652c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic int mcs_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) 653c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 654c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* struct if_irda_req *irq = (struct if_irda_req *)rq; */ 655c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* struct mcs_cb *mcs = netdev_priv(netdev); */ 656c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int ret = 0; 657c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 658c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz switch (cmd) { 659c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz default: 660c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = -EOPNOTSUPP; 661c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 662c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 663c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return ret; 664c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 665c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 666c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Network device is taken down, done by "ifconfig irda0 down" */ 667c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic int mcs_net_close(struct net_device *netdev) 668c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 669c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int ret = 0; 670c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct mcs_cb *mcs = netdev_priv(netdev); 671c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 672c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* Stop transmit processing */ 673c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz netif_stop_queue(netdev); 674c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 6750ff804348d66550e7dd1d6781c65403b312e2da2Hinko Kocevar kfree_skb(mcs->rx_buff.skb); 6760ff804348d66550e7dd1d6781c65403b312e2da2Hinko Kocevar 677c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* kill and free the receive and transmit URBs */ 678c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz usb_kill_urb(mcs->rx_urb); 679c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz usb_free_urb(mcs->rx_urb); 680c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz usb_kill_urb(mcs->tx_urb); 681c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz usb_free_urb(mcs->tx_urb); 682c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 683c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* Stop and remove instance of IrLAP */ 684c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (mcs->irlap) 685c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz irlap_close(mcs->irlap); 686c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 687c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->irlap = NULL; 688c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return ret; 689c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 690c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 691c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Network device is taken up, done by "ifconfig irda0 up" */ 692c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic int mcs_net_open(struct net_device *netdev) 693c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 694c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct mcs_cb *mcs = netdev_priv(netdev); 695c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz char hwname[16]; 696c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int ret = 0; 697c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 698c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = usb_clear_halt(mcs->usbdev, 699c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz usb_sndbulkpipe(mcs->usbdev, mcs->ep_in)); 700c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (ret) 701c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error1; 702c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = usb_clear_halt(mcs->usbdev, 703c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz usb_rcvbulkpipe(mcs->usbdev, mcs->ep_out)); 704c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (ret) 705c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error1; 706c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 707c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_setup_transceiver(mcs); 708c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (ret) 709c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error1; 710c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 711c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = -ENOMEM; 712c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 713c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* Initialize for SIR/FIR to copy data directly into skb. */ 714c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->receiving = 0; 715c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->rx_buff.truesize = IRDA_SKB_MAX_MTU; 716c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); 717c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (!mcs->rx_buff.skb) 718c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error1; 719c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 720c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz skb_reserve(mcs->rx_buff.skb, 1); 721c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->rx_buff.head = mcs->rx_buff.skb->data; 722c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz do_gettimeofday(&mcs->rx_time); 723c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 724c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* 725c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * Now that everything should be initialized properly, 726c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * Open new IrLAP layer instance to take care of us... 727c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * Note : will send immediately a speed change... 728c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 729c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz sprintf(hwname, "usb#%d", mcs->usbdev->devnum); 730c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->irlap = irlap_open(netdev, &mcs->qos, hwname); 731c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (!mcs->irlap) { 732599b1fa91439cff8605a71f1a2b5bb42c177b667Samuel Ortiz IRDA_ERROR("mcs7780: irlap_open failed\n"); 733c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error2; 734c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 735c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 736c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (!mcs_setup_urbs(mcs)) 7379b0f1d85968334c9bbe8675a0fc676c6e15ba577Julia Lawall goto error3; 738c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 739c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_receive_start(mcs); 740c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (ret) 741c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error3; 742c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 743c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz netif_start_queue(netdev); 744c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return 0; 745c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 746c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz error3: 747c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz irlap_close(mcs->irlap); 748c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz error2: 749c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz kfree_skb(mcs->rx_buff.skb); 750c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz error1: 751c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return ret; 752c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 753c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 754c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* Receive callback function. */ 7557d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void mcs_receive_irq(struct urb *urb) 756c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 757c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz __u8 *bytes; 758c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct mcs_cb *mcs = urb->context; 759c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int i; 760c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int ret; 761c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 762c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (!netif_running(mcs->netdev)) 763c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return; 764c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 765c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (urb->status) 766c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return; 767c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 768c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (urb->actual_length > 0) { 769c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz bytes = urb->transfer_buffer; 770c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 771c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* MCS returns frames without BOF and EOF 772c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * I assume it returns whole frames. 773c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 774c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* SIR speed */ 775c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if(mcs->speed < 576000) { 776af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger async_unwrap_char(mcs->netdev, &mcs->netdev->stats, 777c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz &mcs->rx_buff, 0xc0); 778c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 779c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz for (i = 0; i < urb->actual_length; i++) 780af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger async_unwrap_char(mcs->netdev, &mcs->netdev->stats, 781c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz &mcs->rx_buff, bytes[i]); 782c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 783af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger async_unwrap_char(mcs->netdev, &mcs->netdev->stats, 784c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz &mcs->rx_buff, 0xc1); 785c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 786c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* MIR speed */ 787c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz else if(mcs->speed == 576000 || mcs->speed == 1152000) { 788c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs_unwrap_mir(mcs, urb->transfer_buffer, 789c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz urb->actual_length); 790c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 791c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* FIR speed */ 792c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz else { 793c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs_unwrap_fir(mcs, urb->transfer_buffer, 794c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz urb->actual_length); 795c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 796c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz do_gettimeofday(&mcs->rx_time); 797c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 798c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 799c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = usb_submit_urb(urb, GFP_ATOMIC); 800c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 801c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 80225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi/* Transmit callback function. */ 8037d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void mcs_send_irq(struct urb *urb) 804c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 805c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct mcs_cb *mcs = urb->context; 806c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct net_device *ndev = mcs->netdev; 807c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 808c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (unlikely(mcs->new_speed)) 809c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz schedule_work(&mcs->work); 810c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz else 811c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz netif_wake_queue(ndev); 812c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 813c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 81425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi/* Transmit callback function. */ 8156518bbb803fe02b15a3211c8db2afdff0ac4f808Stephen Hemmingerstatic netdev_tx_t mcs_hard_xmit(struct sk_buff *skb, 8166518bbb803fe02b15a3211c8db2afdff0ac4f808Stephen Hemminger struct net_device *ndev) 817c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 818c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz unsigned long flags; 819c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct mcs_cb *mcs; 820c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int wraplen; 821c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int ret = 0; 822c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 823c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz netif_stop_queue(ndev); 824c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs = netdev_priv(ndev); 825c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 826c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz spin_lock_irqsave(&mcs->lock, flags); 827c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 828c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->new_speed = irda_get_next_speed(skb); 829c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (likely(mcs->new_speed == mcs->speed)) 830c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->new_speed = 0; 831c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 832c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* SIR speed */ 833c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if(mcs->speed < 576000) { 834c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz wraplen = mcs_wrap_sir_skb(skb, mcs->out_buf); 835c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 836c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* MIR speed */ 837c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz else if(mcs->speed == 576000 || mcs->speed == 1152000) { 838c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz wraplen = mcs_wrap_mir_skb(skb, mcs->out_buf); 839c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 840c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* FIR speed */ 841c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz else { 842c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz wraplen = mcs_wrap_fir_skb(skb, mcs->out_buf); 843c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 844c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz usb_fill_bulk_urb(mcs->tx_urb, mcs->usbdev, 845c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz usb_sndbulkpipe(mcs->usbdev, mcs->ep_out), 846c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->out_buf, wraplen, mcs_send_irq, mcs); 847c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 848c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if ((ret = usb_submit_urb(mcs->tx_urb, GFP_ATOMIC))) { 849599b1fa91439cff8605a71f1a2b5bb42c177b667Samuel Ortiz IRDA_ERROR("failed tx_urb: %d\n", ret); 850c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz switch (ret) { 851c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz case -ENODEV: 852c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz case -EPIPE: 853c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz break; 854c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz default: 855af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger mcs->netdev->stats.tx_errors++; 856c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz netif_start_queue(ndev); 857c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 858c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } else { 859af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger mcs->netdev->stats.tx_packets++; 860af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger mcs->netdev->stats.tx_bytes += skb->len; 861c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 862c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 863c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz dev_kfree_skb(skb); 864c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz spin_unlock_irqrestore(&mcs->lock, flags); 8654bd73ae2682d9069746bb049a416d9ab90c6684bPatrick McHardy return NETDEV_TX_OK; 866c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 867c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 868ddc2a92d34ba20b47e1856375c68d25f51e86f53Stephen Hemmingerstatic const struct net_device_ops mcs_netdev_ops = { 869ddc2a92d34ba20b47e1856375c68d25f51e86f53Stephen Hemminger .ndo_open = mcs_net_open, 870ddc2a92d34ba20b47e1856375c68d25f51e86f53Stephen Hemminger .ndo_stop = mcs_net_close, 871ddc2a92d34ba20b47e1856375c68d25f51e86f53Stephen Hemminger .ndo_start_xmit = mcs_hard_xmit, 872ddc2a92d34ba20b47e1856375c68d25f51e86f53Stephen Hemminger .ndo_do_ioctl = mcs_net_ioctl, 873ddc2a92d34ba20b47e1856375c68d25f51e86f53Stephen Hemminger}; 874ddc2a92d34ba20b47e1856375c68d25f51e86f53Stephen Hemminger 875c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* 876c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * This function is called by the USB subsystem for each new device in the 877c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz * system. Need to verify the device and if it is, then start handling it. 878c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz */ 879c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic int mcs_probe(struct usb_interface *intf, 880c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz const struct usb_device_id *id) 881c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 882c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct usb_device *udev = interface_to_usbdev(intf); 883c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct net_device *ndev = NULL; 884c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct mcs_cb *mcs; 885c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz int ret = -ENOMEM; 886c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 887c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ndev = alloc_irdadev(sizeof(*mcs)); 888c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (!ndev) 889c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error1; 890c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 891599b1fa91439cff8605a71f1a2b5bb42c177b667Samuel Ortiz IRDA_DEBUG(1, "MCS7780 USB-IrDA bridge found at %d.\n", udev->devnum); 892c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 893c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz SET_NETDEV_DEV(ndev, &intf->dev); 894c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 895c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = usb_reset_configuration(udev); 896c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (ret != 0) { 897599b1fa91439cff8605a71f1a2b5bb42c177b667Samuel Ortiz IRDA_ERROR("mcs7780: usb reset configuration failed\n"); 898c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error2; 899c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 900c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 901c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs = netdev_priv(ndev); 902c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->usbdev = udev; 903c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->netdev = ndev; 904c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz spin_lock_init(&mcs->lock); 905c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 906c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* Initialize QoS for this device */ 907c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz irda_init_max_qos_capabilies(&mcs->qos); 908c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 909c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* That's the Rx capability. */ 910c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->qos.baud_rate.bits &= 911c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200 912c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz | IR_576000 | IR_1152000 | (IR_4000000 << 8); 913c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 914c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 915c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->qos.min_turn_time.bits &= qos_mtt_bits; 916c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz irda_qos_bits_to_value(&mcs->qos); 917c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 918c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz /* Speed change work initialisation*/ 919c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_WORK(&mcs->work, mcs_speed_work); 920c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 921ddc2a92d34ba20b47e1856375c68d25f51e86f53Stephen Hemminger ndev->netdev_ops = &mcs_netdev_ops; 922c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 923c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (!intf->cur_altsetting) 924c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error2; 925c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 926c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = mcs_find_endpoints(mcs, intf->cur_altsetting->endpoint, 927c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz intf->cur_altsetting->desc.bNumEndpoints); 928c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (!ret) { 929c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = -ENODEV; 930c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error2; 931c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz } 932c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 933c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ret = register_netdev(ndev); 934c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (ret != 0) 935c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz goto error2; 936c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 937599b1fa91439cff8605a71f1a2b5bb42c177b667Samuel Ortiz IRDA_DEBUG(1, "IrDA: Registered MosChip MCS7780 device as %s\n", 938c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz ndev->name); 939c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 940c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->transceiver_type = transceiver_type; 941c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->sir_tweak = sir_tweak; 942c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz mcs->receive_mode = receive_mode; 943c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 944c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz usb_set_intfdata(intf, mcs); 945c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return 0; 946c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 947c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz error2: 948c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz free_netdev(ndev); 949c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 950c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz error1: 951c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return ret; 952c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 953c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 954c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz/* The current device is removed, the USB layer tells us to shut down. */ 955c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortizstatic void mcs_disconnect(struct usb_interface *intf) 956c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz{ 957c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz struct mcs_cb *mcs = usb_get_intfdata(intf); 958c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 959c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz if (!mcs) 960c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz return; 961c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 96223f333a2bfafba80339315b724808982a9de57d9Tejun Heo cancel_work_sync(&mcs->work); 963c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 964c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz unregister_netdev(mcs->netdev); 965c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz free_netdev(mcs->netdev); 966c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 967c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz usb_set_intfdata(intf, NULL); 968599b1fa91439cff8605a71f1a2b5bb42c177b667Samuel Ortiz IRDA_DEBUG(0, "MCS7780 now disconnected.\n"); 969c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz} 970c6ae522e3a50fc1ec483d7f03ece9c7a25e6de95Samuel Ortiz 971d632eb1bf22e11def74e4e53cc47d790fbdba105Greg Kroah-Hartmanmodule_usb_driver(mcs_driver); 972