10f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* 20f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720.c 30f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Controls the Moschip 7720 usb to dual port serial convertor 40f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 50f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Copyright 2006 Moschip Semiconductor Tech. Ltd. 60f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 70f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * This program is free software; you can redistribute it and/or modify 80f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * it under the terms of the GNU General Public License as published by 90f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * the Free Software Foundation, version 2 of the License. 100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Developed by: 1250d2dc7266573dfbdc84fc207494dd21315782efGreg Kroah-Hartman * Vijaya Kumar <vijaykumar.gn@gmail.com> 1350d2dc7266573dfbdc84fc207494dd21315782efGreg Kroah-Hartman * Ajay Kumar <naanuajay@yahoo.com> 1450d2dc7266573dfbdc84fc207494dd21315782efGreg Kroah-Hartman * Gurudeva <ngurudeva@yahoo.com> 150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Cleaned up from the original by: 170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Greg Kroah-Hartman <gregkh@suse.de> 180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Originally based on drivers/usb/serial/io_edgeport.c which is: 200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Copyright (C) 2000 Inside Out Networks, All rights reserved. 210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> 220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */ 230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/kernel.h> 240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/errno.h> 250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/init.h> 260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/slab.h> 270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/tty.h> 280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/tty_driver.h> 290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/tty_flip.h> 300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/module.h> 310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/spinlock.h> 320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/serial.h> 330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/serial_reg.h> 340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/usb.h> 350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/usb/serial.h> 364da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox#include <linux/uaccess.h> 37b69578df7e98659b7d94c905971a6d1025b431adMike Dunn#include <linux/parport.h> 380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* 400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Version Information 410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */ 4263b917678fe6d63e633462b5be5a309511bcf3caMike Dunn#define DRIVER_VERSION "2.1" 430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define DRIVER_AUTHOR "Aspire Communications pvt Ltd." 440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define DRIVER_DESC "Moschip USB Serial Driver" 450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* default urb timeout */ 470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOS_WDR_TIMEOUT (HZ * 5) 480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOS_MAX_PORT 0x02 500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOS_WRITE 0x0E 510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOS_READ 0x0D 520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* Interrupt Rotinue Defines */ 540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define SERIAL_IIR_RLS 0x06 550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define SERIAL_IIR_RDA 0x04 560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define SERIAL_IIR_CTI 0x0c 570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define SERIAL_IIR_THR 0x02 580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define SERIAL_IIR_MS 0x00 590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define NUM_URBS 16 /* URB Count */ 610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ 620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 63b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* This structure holds all of the local serial port information */ 644da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Coxstruct moschip_port { 650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman __u8 shadowLCR; /* last LCR value received */ 660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman __u8 shadowMCR; /* last MCR value received */ 670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman __u8 shadowMSR; /* last MSR value received */ 680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman char open; 690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct async_icount icount; 700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_serial_port *port; /* loop back to the owner */ 710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct urb *write_urb_pool[NUM_URBS]; 720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}; 730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 7490ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool debug; 750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 76fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunnstatic struct usb_serial_driver moschip7720_2port_driver; 77fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn 780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define USB_VENDOR_ID_MOSCHIP 0x9710 790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOSCHIP_DEVICE_ID_7720 0x7720 800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOSCHIP_DEVICE_ID_7715 0x7715 810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 827d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id moschip_port_id_table[] = { 834da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) }, 84fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7715) }, 850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { } /* terminating entry */ 860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}; 870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-HartmanMODULE_DEVICE_TABLE(usb, moschip_port_id_table); 880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 89b69578df7e98659b7d94c905971a6d1025b431adMike Dunn#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT 90b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 91b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* initial values for parport regs */ 92b69578df7e98659b7d94c905971a6d1025b431adMike Dunn#define DCR_INIT_VAL 0x0c /* SLCTIN, nINIT */ 93b69578df7e98659b7d94c905971a6d1025b431adMike Dunn#define ECR_INIT_VAL 0x00 /* SPP mode */ 94b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 95b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstruct urbtracker { 96b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport; 97b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct list_head urblist_entry; 98b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct kref ref_count; 99b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct urb *urb; 100b69578df7e98659b7d94c905971a6d1025b431adMike Dunn}; 101b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 102b69578df7e98659b7d94c905971a6d1025b431adMike Dunnenum mos7715_pp_modes { 103b69578df7e98659b7d94c905971a6d1025b431adMike Dunn SPP = 0<<5, 104b69578df7e98659b7d94c905971a6d1025b431adMike Dunn PS2 = 1<<5, /* moschip calls this 'NIBBLE' mode */ 105b69578df7e98659b7d94c905971a6d1025b431adMike Dunn PPF = 2<<5, /* moschip calls this 'CB-FIFO mode */ 106b69578df7e98659b7d94c905971a6d1025b431adMike Dunn}; 107b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 108b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstruct mos7715_parport { 109b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct parport *pp; /* back to containing struct */ 110b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct kref ref_count; /* to instance of this struct */ 111b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct list_head deferred_urbs; /* list deferred async urbs */ 112b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct list_head active_urbs; /* list async urbs in flight */ 113b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spinlock_t listlock; /* protects list access */ 114b69578df7e98659b7d94c905971a6d1025b431adMike Dunn bool msg_pending; /* usb sync call pending */ 115b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct completion syncmsg_compl; /* usb sync call completed */ 116b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct tasklet_struct urb_tasklet; /* for sending deferred urbs */ 117b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct usb_serial *serial; /* back to containing struct */ 118b69578df7e98659b7d94c905971a6d1025b431adMike Dunn __u8 shadowECR; /* parallel port regs... */ 119b69578df7e98659b7d94c905971a6d1025b431adMike Dunn __u8 shadowDCR; 120b69578df7e98659b7d94c905971a6d1025b431adMike Dunn atomic_t shadowDSR; /* updated in int-in callback */ 121b69578df7e98659b7d94c905971a6d1025b431adMike Dunn}; 122b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 123b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* lock guards against dereferencing NULL ptr in parport ops callbacks */ 124b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic DEFINE_SPINLOCK(release_lock); 125b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 12663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn#endif /* CONFIG_USB_SERIAL_MOS7715_PARPORT */ 12763b917678fe6d63e633462b5be5a309511bcf3caMike Dunn 12863b917678fe6d63e633462b5be5a309511bcf3caMike Dunnstatic const unsigned int dummy; /* for clarity in register access fns */ 12963b917678fe6d63e633462b5be5a309511bcf3caMike Dunn 130b69578df7e98659b7d94c905971a6d1025b431adMike Dunnenum mos_regs { 131b69578df7e98659b7d94c905971a6d1025b431adMike Dunn THR, /* serial port regs */ 132b69578df7e98659b7d94c905971a6d1025b431adMike Dunn RHR, 133b69578df7e98659b7d94c905971a6d1025b431adMike Dunn IER, 134b69578df7e98659b7d94c905971a6d1025b431adMike Dunn FCR, 135b69578df7e98659b7d94c905971a6d1025b431adMike Dunn ISR, 136b69578df7e98659b7d94c905971a6d1025b431adMike Dunn LCR, 137b69578df7e98659b7d94c905971a6d1025b431adMike Dunn MCR, 138b69578df7e98659b7d94c905971a6d1025b431adMike Dunn LSR, 139b69578df7e98659b7d94c905971a6d1025b431adMike Dunn MSR, 140b69578df7e98659b7d94c905971a6d1025b431adMike Dunn SPR, 141b69578df7e98659b7d94c905971a6d1025b431adMike Dunn DLL, 142b69578df7e98659b7d94c905971a6d1025b431adMike Dunn DLM, 143b69578df7e98659b7d94c905971a6d1025b431adMike Dunn DPR, /* parallel port regs */ 144b69578df7e98659b7d94c905971a6d1025b431adMike Dunn DSR, 145b69578df7e98659b7d94c905971a6d1025b431adMike Dunn DCR, 146b69578df7e98659b7d94c905971a6d1025b431adMike Dunn ECR, 147b69578df7e98659b7d94c905971a6d1025b431adMike Dunn SP1_REG, /* device control regs */ 148b69578df7e98659b7d94c905971a6d1025b431adMike Dunn SP2_REG, /* serial port 2 (7720 only) */ 149b69578df7e98659b7d94c905971a6d1025b431adMike Dunn PP_REG, 150b69578df7e98659b7d94c905971a6d1025b431adMike Dunn SP_CONTROL_REG, 151b69578df7e98659b7d94c905971a6d1025b431adMike Dunn}; 152b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 153b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* 154b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * Return the correct value for the Windex field of the setup packet 155b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * for a control endpoint message. See the 7715 datasheet. 156b69578df7e98659b7d94c905971a6d1025b431adMike Dunn */ 157b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic inline __u16 get_reg_index(enum mos_regs reg) 158b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 159b69578df7e98659b7d94c905971a6d1025b431adMike Dunn static const __u16 mos7715_index_lookup_table[] = { 160b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x00, /* THR */ 161b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x00, /* RHR */ 162b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x01, /* IER */ 163b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x02, /* FCR */ 164b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x02, /* ISR */ 165b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x03, /* LCR */ 166b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x04, /* MCR */ 167b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x05, /* LSR */ 168b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x06, /* MSR */ 169b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x07, /* SPR */ 170b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x00, /* DLL */ 171b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x01, /* DLM */ 172b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x00, /* DPR */ 173b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x01, /* DSR */ 174b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x02, /* DCR */ 175b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x0a, /* ECR */ 176b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x01, /* SP1_REG */ 177b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x02, /* SP2_REG (7720 only) */ 178b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x04, /* PP_REG (7715 only) */ 179b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 0x08, /* SP_CONTROL_REG */ 180b69578df7e98659b7d94c905971a6d1025b431adMike Dunn }; 181b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return mos7715_index_lookup_table[reg]; 182b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 183b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 184b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* 185b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * Return the correct value for the upper byte of the Wvalue field of 186b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * the setup packet for a control endpoint message. 187b69578df7e98659b7d94c905971a6d1025b431adMike Dunn */ 18863b917678fe6d63e633462b5be5a309511bcf3caMike Dunnstatic inline __u16 get_reg_value(enum mos_regs reg, 18963b917678fe6d63e633462b5be5a309511bcf3caMike Dunn unsigned int serial_portnum) 190b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 191b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (reg >= SP1_REG) /* control reg */ 192b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return 0x0000; 19363b917678fe6d63e633462b5be5a309511bcf3caMike Dunn 19463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn else if (reg >= DPR) /* parallel port reg (7715 only) */ 195b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return 0x0100; 19663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn 19763b917678fe6d63e633462b5be5a309511bcf3caMike Dunn else /* serial port reg */ 19863b917678fe6d63e633462b5be5a309511bcf3caMike Dunn return (serial_portnum + 2) << 8; 199b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 200b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 201b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* 202b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * Write data byte to the specified device register. The data is embedded in 20363b917678fe6d63e633462b5be5a309511bcf3caMike Dunn * the value field of the setup packet. serial_portnum is ignored for registers 20463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn * not specific to a particular serial port. 205b69578df7e98659b7d94c905971a6d1025b431adMike Dunn */ 20663b917678fe6d63e633462b5be5a309511bcf3caMike Dunnstatic int write_mos_reg(struct usb_serial *serial, unsigned int serial_portnum, 20763b917678fe6d63e633462b5be5a309511bcf3caMike Dunn enum mos_regs reg, __u8 data) 208b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 209b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct usb_device *usbdev = serial->dev; 210b69578df7e98659b7d94c905971a6d1025b431adMike Dunn unsigned int pipe = usb_sndctrlpipe(usbdev, 0); 211b69578df7e98659b7d94c905971a6d1025b431adMike Dunn __u8 request = (__u8)0x0e; 212b69578df7e98659b7d94c905971a6d1025b431adMike Dunn __u8 requesttype = (__u8)0x40; 213b69578df7e98659b7d94c905971a6d1025b431adMike Dunn __u16 index = get_reg_index(reg); 21463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn __u16 value = get_reg_value(reg, serial_portnum) + data; 21563b917678fe6d63e633462b5be5a309511bcf3caMike Dunn int status = usb_control_msg(usbdev, pipe, request, requesttype, value, 21663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn index, NULL, 0, MOS_WDR_TIMEOUT); 217b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (status < 0) 218b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dev_err(&usbdev->dev, 219b69578df7e98659b7d94c905971a6d1025b431adMike Dunn "mos7720: usb_control_msg() failed: %d", status); 220b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return status; 221b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 222b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 223b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* 224b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * Read data byte from the specified device register. The data returned by the 22563b917678fe6d63e633462b5be5a309511bcf3caMike Dunn * device is embedded in the value field of the setup packet. serial_portnum is 22663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn * ignored for registers that are not specific to a particular serial port. 227b69578df7e98659b7d94c905971a6d1025b431adMike Dunn */ 22863b917678fe6d63e633462b5be5a309511bcf3caMike Dunnstatic int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum, 22963b917678fe6d63e633462b5be5a309511bcf3caMike Dunn enum mos_regs reg, __u8 *data) 230b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 23163b917678fe6d63e633462b5be5a309511bcf3caMike Dunn struct usb_device *usbdev = serial->dev; 232b69578df7e98659b7d94c905971a6d1025b431adMike Dunn unsigned int pipe = usb_rcvctrlpipe(usbdev, 0); 233b69578df7e98659b7d94c905971a6d1025b431adMike Dunn __u8 request = (__u8)0x0d; 234b69578df7e98659b7d94c905971a6d1025b431adMike Dunn __u8 requesttype = (__u8)0xc0; 235b69578df7e98659b7d94c905971a6d1025b431adMike Dunn __u16 index = get_reg_index(reg); 23663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn __u16 value = get_reg_value(reg, serial_portnum); 237b69578df7e98659b7d94c905971a6d1025b431adMike Dunn int status = usb_control_msg(usbdev, pipe, request, requesttype, value, 23863b917678fe6d63e633462b5be5a309511bcf3caMike Dunn index, data, 1, MOS_WDR_TIMEOUT); 239b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (status < 0) 240b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dev_err(&usbdev->dev, 241b69578df7e98659b7d94c905971a6d1025b431adMike Dunn "mos7720: usb_control_msg() failed: %d", status); 242b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return status; 243b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 244b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 24563b917678fe6d63e633462b5be5a309511bcf3caMike Dunn#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT 24663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn 247b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic inline int mos7715_change_mode(struct mos7715_parport *mos_parport, 248b69578df7e98659b7d94c905971a6d1025b431adMike Dunn enum mos7715_pp_modes mode) 249b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 250b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->shadowECR = mode; 25163b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(mos_parport->serial, dummy, ECR, mos_parport->shadowECR); 252b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return 0; 253b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 254b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 255b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic void destroy_mos_parport(struct kref *kref) 256b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 257b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = 258b69578df7e98659b7d94c905971a6d1025b431adMike Dunn container_of(kref, struct mos7715_parport, ref_count); 259b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 260b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 261b69578df7e98659b7d94c905971a6d1025b431adMike Dunn kfree(mos_parport); 262b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 263b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 264b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic void destroy_urbtracker(struct kref *kref) 265b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 266b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct urbtracker *urbtrack = 267b69578df7e98659b7d94c905971a6d1025b431adMike Dunn container_of(kref, struct urbtracker, ref_count); 268b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = urbtrack->mos_parport; 269b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 270b69578df7e98659b7d94c905971a6d1025b431adMike Dunn usb_free_urb(urbtrack->urb); 271b69578df7e98659b7d94c905971a6d1025b431adMike Dunn kfree(urbtrack); 272b69578df7e98659b7d94c905971a6d1025b431adMike Dunn kref_put(&mos_parport->ref_count, destroy_mos_parport); 273b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 274b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 275b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* 276b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * This runs as a tasklet when sending an urb in a non-blocking parallel 277b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * port callback had to be deferred because the disconnect mutex could not be 278b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * obtained at the time. 279b69578df7e98659b7d94c905971a6d1025b431adMike Dunn */ 280b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic void send_deferred_urbs(unsigned long _mos_parport) 281b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 282b69578df7e98659b7d94c905971a6d1025b431adMike Dunn int ret_val; 283b69578df7e98659b7d94c905971a6d1025b431adMike Dunn unsigned long flags; 284b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = (void *)_mos_parport; 285b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct urbtracker *urbtrack; 286b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct list_head *cursor, *next; 287b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 288b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 289b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 290b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* if release function ran, game over */ 291b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (unlikely(mos_parport->serial == NULL)) 292b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return; 293b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 294b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* try again to get the mutex */ 295b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (!mutex_trylock(&mos_parport->serial->disc_mutex)) { 296b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s: rescheduling tasklet", __func__); 297b69578df7e98659b7d94c905971a6d1025b431adMike Dunn tasklet_schedule(&mos_parport->urb_tasklet); 298b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return; 299b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 300b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 301b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* if device disconnected, game over */ 302b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (unlikely(mos_parport->serial->disconnected)) { 303b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mutex_unlock(&mos_parport->serial->disc_mutex); 304b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return; 305b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 306b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 307b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_lock_irqsave(&mos_parport->listlock, flags); 308b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (list_empty(&mos_parport->deferred_urbs)) { 309b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock_irqrestore(&mos_parport->listlock, flags); 310b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mutex_unlock(&mos_parport->serial->disc_mutex); 311b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s: deferred_urbs list empty", __func__); 312b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return; 313b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 314b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 315b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* move contents of deferred_urbs list to active_urbs list and submit */ 316b69578df7e98659b7d94c905971a6d1025b431adMike Dunn list_for_each_safe(cursor, next, &mos_parport->deferred_urbs) 317b69578df7e98659b7d94c905971a6d1025b431adMike Dunn list_move_tail(cursor, &mos_parport->active_urbs); 318b69578df7e98659b7d94c905971a6d1025b431adMike Dunn list_for_each_entry(urbtrack, &mos_parport->active_urbs, 319b69578df7e98659b7d94c905971a6d1025b431adMike Dunn urblist_entry) { 320b69578df7e98659b7d94c905971a6d1025b431adMike Dunn ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC); 321b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s: urb submitted", __func__); 322b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (ret_val) { 323b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dev_err(&mos_parport->serial->dev->dev, 324b69578df7e98659b7d94c905971a6d1025b431adMike Dunn "usb_submit_urb() failed: %d", ret_val); 325b69578df7e98659b7d94c905971a6d1025b431adMike Dunn list_del(&urbtrack->urblist_entry); 326b69578df7e98659b7d94c905971a6d1025b431adMike Dunn kref_put(&urbtrack->ref_count, destroy_urbtracker); 327b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 328b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 329b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock_irqrestore(&mos_parport->listlock, flags); 330b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mutex_unlock(&mos_parport->serial->disc_mutex); 331b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 332b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 333b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* callback for parallel port control urbs submitted asynchronously */ 334b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic void async_complete(struct urb *urb) 335b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 336b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct urbtracker *urbtrack = urb->context; 337b69578df7e98659b7d94c905971a6d1025b431adMike Dunn int status = urb->status; 338b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 339b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (unlikely(status)) 340b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s - nonzero urb status received: %d", __func__, status); 341b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 342b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* remove the urbtracker from the active_urbs list */ 343b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_lock(&urbtrack->mos_parport->listlock); 344b69578df7e98659b7d94c905971a6d1025b431adMike Dunn list_del(&urbtrack->urblist_entry); 345b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock(&urbtrack->mos_parport->listlock); 346b69578df7e98659b7d94c905971a6d1025b431adMike Dunn kref_put(&urbtrack->ref_count, destroy_urbtracker); 347b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 348b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 349b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, 350b69578df7e98659b7d94c905971a6d1025b431adMike Dunn enum mos_regs reg, __u8 data) 351b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 352b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct urbtracker *urbtrack; 353b69578df7e98659b7d94c905971a6d1025b431adMike Dunn int ret_val; 354b69578df7e98659b7d94c905971a6d1025b431adMike Dunn unsigned long flags; 355b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct usb_ctrlrequest setup; 356b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct usb_serial *serial = mos_parport->serial; 357b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct usb_device *usbdev = serial->dev; 358b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 359b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 360b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* create and initialize the control urb and containing urbtracker */ 361b69578df7e98659b7d94c905971a6d1025b431adMike Dunn urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC); 362b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (urbtrack == NULL) { 363b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dev_err(&usbdev->dev, "out of memory"); 364b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return -ENOMEM; 365b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 366b69578df7e98659b7d94c905971a6d1025b431adMike Dunn kref_get(&mos_parport->ref_count); 367b69578df7e98659b7d94c905971a6d1025b431adMike Dunn urbtrack->mos_parport = mos_parport; 368b69578df7e98659b7d94c905971a6d1025b431adMike Dunn urbtrack->urb = usb_alloc_urb(0, GFP_ATOMIC); 369b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (urbtrack->urb == NULL) { 370b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dev_err(&usbdev->dev, "out of urbs"); 371b69578df7e98659b7d94c905971a6d1025b431adMike Dunn kfree(urbtrack); 372b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return -ENOMEM; 373b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 374b69578df7e98659b7d94c905971a6d1025b431adMike Dunn setup.bRequestType = (__u8)0x40; 375b69578df7e98659b7d94c905971a6d1025b431adMike Dunn setup.bRequest = (__u8)0x0e; 37663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn setup.wValue = get_reg_value(reg, dummy); 377b69578df7e98659b7d94c905971a6d1025b431adMike Dunn setup.wIndex = get_reg_index(reg); 378b69578df7e98659b7d94c905971a6d1025b431adMike Dunn setup.wLength = 0; 379b69578df7e98659b7d94c905971a6d1025b431adMike Dunn usb_fill_control_urb(urbtrack->urb, usbdev, 380b69578df7e98659b7d94c905971a6d1025b431adMike Dunn usb_sndctrlpipe(usbdev, 0), 381b69578df7e98659b7d94c905971a6d1025b431adMike Dunn (unsigned char *)&setup, 382b69578df7e98659b7d94c905971a6d1025b431adMike Dunn NULL, 0, async_complete, urbtrack); 383b69578df7e98659b7d94c905971a6d1025b431adMike Dunn kref_init(&urbtrack->ref_count); 384b69578df7e98659b7d94c905971a6d1025b431adMike Dunn INIT_LIST_HEAD(&urbtrack->urblist_entry); 385b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 386b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* 387b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * get the disconnect mutex, or add tracker to the deferred_urbs list 388b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * and schedule a tasklet to try again later 389b69578df7e98659b7d94c905971a6d1025b431adMike Dunn */ 390b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (!mutex_trylock(&serial->disc_mutex)) { 391b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_lock_irqsave(&mos_parport->listlock, flags); 392b69578df7e98659b7d94c905971a6d1025b431adMike Dunn list_add_tail(&urbtrack->urblist_entry, 393b69578df7e98659b7d94c905971a6d1025b431adMike Dunn &mos_parport->deferred_urbs); 394b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock_irqrestore(&mos_parport->listlock, flags); 395b69578df7e98659b7d94c905971a6d1025b431adMike Dunn tasklet_schedule(&mos_parport->urb_tasklet); 396b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("tasklet scheduled"); 397b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return 0; 398b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 399b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 400b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* bail if device disconnected */ 401b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (serial->disconnected) { 402b69578df7e98659b7d94c905971a6d1025b431adMike Dunn kref_put(&urbtrack->ref_count, destroy_urbtracker); 403b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mutex_unlock(&serial->disc_mutex); 404b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return -ENODEV; 405b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 406b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 407b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* add the tracker to the active_urbs list and submit */ 408b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_lock_irqsave(&mos_parport->listlock, flags); 409b69578df7e98659b7d94c905971a6d1025b431adMike Dunn list_add_tail(&urbtrack->urblist_entry, &mos_parport->active_urbs); 410b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock_irqrestore(&mos_parport->listlock, flags); 411b69578df7e98659b7d94c905971a6d1025b431adMike Dunn ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC); 412b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mutex_unlock(&serial->disc_mutex); 413b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (ret_val) { 414b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dev_err(&usbdev->dev, 415b69578df7e98659b7d94c905971a6d1025b431adMike Dunn "%s: submit_urb() failed: %d", __func__, ret_val); 416b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_lock_irqsave(&mos_parport->listlock, flags); 417b69578df7e98659b7d94c905971a6d1025b431adMike Dunn list_del(&urbtrack->urblist_entry); 418b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock_irqrestore(&mos_parport->listlock, flags); 419b69578df7e98659b7d94c905971a6d1025b431adMike Dunn kref_put(&urbtrack->ref_count, destroy_urbtracker); 420b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return ret_val; 421b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 422b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return 0; 423b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 424b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 425b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* 426b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * This is the the common top part of all parallel port callback operations that 427b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * send synchronous messages to the device. This implements convoluted locking 428b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * that avoids two scenarios: (1) a port operation is called after usbserial 429b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * has called our release function, at which point struct mos7715_parport has 430b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * been destroyed, and (2) the device has been disconnected, but usbserial has 431b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * not called the release function yet because someone has a serial port open. 432b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * The shared release_lock prevents the first, and the mutex and disconnected 433b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * flag maintained by usbserial covers the second. We also use the msg_pending 434b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * flag to ensure that all synchronous usb messgage calls have completed before 435b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * our release function can return. 436b69578df7e98659b7d94c905971a6d1025b431adMike Dunn */ 437b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic int parport_prologue(struct parport *pp) 438b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 439b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport; 440b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 441b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_lock(&release_lock); 442b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport = pp->private_data; 443b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (unlikely(mos_parport == NULL)) { 444b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* release fn called, port struct destroyed */ 445b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock(&release_lock); 446b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return -1; 447b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 448b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->msg_pending = true; /* synch usb call pending */ 449b69578df7e98659b7d94c905971a6d1025b431adMike Dunn INIT_COMPLETION(mos_parport->syncmsg_compl); 450b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock(&release_lock); 451b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 452b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mutex_lock(&mos_parport->serial->disc_mutex); 453b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (mos_parport->serial->disconnected) { 454b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* device disconnected */ 455b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mutex_unlock(&mos_parport->serial->disc_mutex); 456b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->msg_pending = false; 457b69578df7e98659b7d94c905971a6d1025b431adMike Dunn complete(&mos_parport->syncmsg_compl); 458b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return -1; 459b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 460b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 461b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return 0; 462b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 463b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 464b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* 465b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * This is the the common bottom part of all parallel port functions that send 466b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * synchronous messages to the device. 467b69578df7e98659b7d94c905971a6d1025b431adMike Dunn */ 468b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic inline void parport_epilogue(struct parport *pp) 469b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 470b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = pp->private_data; 471b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mutex_unlock(&mos_parport->serial->disc_mutex); 472b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->msg_pending = false; 473b69578df7e98659b7d94c905971a6d1025b431adMike Dunn complete(&mos_parport->syncmsg_compl); 474b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 475b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 476b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic void parport_mos7715_write_data(struct parport *pp, unsigned char d) 477b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 478b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = pp->private_data; 479b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called: %2.2x", __func__, d); 480b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (parport_prologue(pp) < 0) 481b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return; 482b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos7715_change_mode(mos_parport, SPP); 48363b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(mos_parport->serial, dummy, DPR, (__u8)d); 484b69578df7e98659b7d94c905971a6d1025b431adMike Dunn parport_epilogue(pp); 485b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 486b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 487b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic unsigned char parport_mos7715_read_data(struct parport *pp) 488b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 489b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = pp->private_data; 490b69578df7e98659b7d94c905971a6d1025b431adMike Dunn unsigned char d; 491b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 492b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (parport_prologue(pp) < 0) 493b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return 0; 49463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn read_mos_reg(mos_parport->serial, dummy, DPR, &d); 495b69578df7e98659b7d94c905971a6d1025b431adMike Dunn parport_epilogue(pp); 496b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return d; 497b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 498b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 499b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic void parport_mos7715_write_control(struct parport *pp, unsigned char d) 500b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 501b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = pp->private_data; 502b69578df7e98659b7d94c905971a6d1025b431adMike Dunn __u8 data; 503b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called: %2.2x", __func__, d); 504b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (parport_prologue(pp) < 0) 505b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return; 506b69578df7e98659b7d94c905971a6d1025b431adMike Dunn data = ((__u8)d & 0x0f) | (mos_parport->shadowDCR & 0xf0); 50763b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(mos_parport->serial, dummy, DCR, data); 508b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->shadowDCR = data; 509b69578df7e98659b7d94c905971a6d1025b431adMike Dunn parport_epilogue(pp); 510b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 511b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 512b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic unsigned char parport_mos7715_read_control(struct parport *pp) 513b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 514b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = pp->private_data; 515b69578df7e98659b7d94c905971a6d1025b431adMike Dunn __u8 dcr; 516b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 517b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_lock(&release_lock); 518b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport = pp->private_data; 519b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (unlikely(mos_parport == NULL)) { 520b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock(&release_lock); 521b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return 0; 522b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 523b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dcr = mos_parport->shadowDCR & 0x0f; 524b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock(&release_lock); 525b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return dcr; 526b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 527b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 528b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic unsigned char parport_mos7715_frob_control(struct parport *pp, 529b69578df7e98659b7d94c905971a6d1025b431adMike Dunn unsigned char mask, 530b69578df7e98659b7d94c905971a6d1025b431adMike Dunn unsigned char val) 531b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 532b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = pp->private_data; 533b69578df7e98659b7d94c905971a6d1025b431adMike Dunn __u8 dcr; 534b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 535b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mask &= 0x0f; 536b69578df7e98659b7d94c905971a6d1025b431adMike Dunn val &= 0x0f; 537b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (parport_prologue(pp) < 0) 538b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return 0; 539b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->shadowDCR = (mos_parport->shadowDCR & (~mask)) ^ val; 54063b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR); 541b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dcr = mos_parport->shadowDCR & 0x0f; 542b69578df7e98659b7d94c905971a6d1025b431adMike Dunn parport_epilogue(pp); 543b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return dcr; 544b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 545b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 546b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic unsigned char parport_mos7715_read_status(struct parport *pp) 547b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 548b69578df7e98659b7d94c905971a6d1025b431adMike Dunn unsigned char status; 549b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = pp->private_data; 550b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 551b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_lock(&release_lock); 552b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport = pp->private_data; 553b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (unlikely(mos_parport == NULL)) { /* release called */ 554b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock(&release_lock); 555b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return 0; 556b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 557b69578df7e98659b7d94c905971a6d1025b431adMike Dunn status = atomic_read(&mos_parport->shadowDSR) & 0xf8; 558b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock(&release_lock); 559b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return status; 560b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 561b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 562b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic void parport_mos7715_enable_irq(struct parport *pp) 563b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 564b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 565b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 566b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic void parport_mos7715_disable_irq(struct parport *pp) 567b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 568b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 569b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 570b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 571b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic void parport_mos7715_data_forward(struct parport *pp) 572b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 573b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = pp->private_data; 574b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 575b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (parport_prologue(pp) < 0) 576b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return; 577b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos7715_change_mode(mos_parport, PS2); 578b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->shadowDCR &= ~0x20; 57963b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR); 580b69578df7e98659b7d94c905971a6d1025b431adMike Dunn parport_epilogue(pp); 581b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 582b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 583b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic void parport_mos7715_data_reverse(struct parport *pp) 584b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 585b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = pp->private_data; 586b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 587b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (parport_prologue(pp) < 0) 588b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return; 589b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos7715_change_mode(mos_parport, PS2); 590b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->shadowDCR |= 0x20; 59163b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR); 592b69578df7e98659b7d94c905971a6d1025b431adMike Dunn parport_epilogue(pp); 593b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 594b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 595b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic void parport_mos7715_init_state(struct pardevice *dev, 596b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct parport_state *s) 597b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 598b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 599b69578df7e98659b7d94c905971a6d1025b431adMike Dunn s->u.pc.ctr = DCR_INIT_VAL; 600b69578df7e98659b7d94c905971a6d1025b431adMike Dunn s->u.pc.ecr = ECR_INIT_VAL; 601b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 602b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 603b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* N.B. Parport core code requires that this function not block */ 604b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic void parport_mos7715_save_state(struct parport *pp, 605b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct parport_state *s) 606b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 607b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport; 608b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 609b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_lock(&release_lock); 610b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport = pp->private_data; 611b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (unlikely(mos_parport == NULL)) { /* release called */ 612b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock(&release_lock); 613b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return; 614b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 615b69578df7e98659b7d94c905971a6d1025b431adMike Dunn s->u.pc.ctr = mos_parport->shadowDCR; 616b69578df7e98659b7d94c905971a6d1025b431adMike Dunn s->u.pc.ecr = mos_parport->shadowECR; 617b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock(&release_lock); 618b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 619b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 620b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* N.B. Parport core code requires that this function not block */ 621b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic void parport_mos7715_restore_state(struct parport *pp, 622b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct parport_state *s) 623b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 624b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport; 625b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called", __func__); 626b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_lock(&release_lock); 627b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport = pp->private_data; 628b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (unlikely(mos_parport == NULL)) { /* release called */ 629b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock(&release_lock); 630b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return; 631b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 632b69578df7e98659b7d94c905971a6d1025b431adMike Dunn write_parport_reg_nonblock(mos_parport, DCR, mos_parport->shadowDCR); 633b69578df7e98659b7d94c905971a6d1025b431adMike Dunn write_parport_reg_nonblock(mos_parport, ECR, mos_parport->shadowECR); 634b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock(&release_lock); 635b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 636b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 637b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic size_t parport_mos7715_write_compat(struct parport *pp, 638b69578df7e98659b7d94c905971a6d1025b431adMike Dunn const void *buffer, 639b69578df7e98659b7d94c905971a6d1025b431adMike Dunn size_t len, int flags) 640b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 641b69578df7e98659b7d94c905971a6d1025b431adMike Dunn int retval; 642b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = pp->private_data; 643b69578df7e98659b7d94c905971a6d1025b431adMike Dunn int actual_len; 644b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s called: %u chars", __func__, (unsigned int)len); 645b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (parport_prologue(pp) < 0) 646b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return 0; 647b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos7715_change_mode(mos_parport, PPF); 648b69578df7e98659b7d94c905971a6d1025b431adMike Dunn retval = usb_bulk_msg(mos_parport->serial->dev, 649b69578df7e98659b7d94c905971a6d1025b431adMike Dunn usb_sndbulkpipe(mos_parport->serial->dev, 2), 650b69578df7e98659b7d94c905971a6d1025b431adMike Dunn (void *)buffer, len, &actual_len, 651b69578df7e98659b7d94c905971a6d1025b431adMike Dunn MOS_WDR_TIMEOUT); 652b69578df7e98659b7d94c905971a6d1025b431adMike Dunn parport_epilogue(pp); 653b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (retval) { 654b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dev_err(&mos_parport->serial->dev->dev, 655b69578df7e98659b7d94c905971a6d1025b431adMike Dunn "mos7720: usb_bulk_msg() failed: %d", retval); 656b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return 0; 657b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 658b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return actual_len; 659b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 660b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 661b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic struct parport_operations parport_mos7715_ops = { 662b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .owner = THIS_MODULE, 663b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .write_data = parport_mos7715_write_data, 664b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .read_data = parport_mos7715_read_data, 665b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 666b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .write_control = parport_mos7715_write_control, 667b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .read_control = parport_mos7715_read_control, 668b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .frob_control = parport_mos7715_frob_control, 669b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 670b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .read_status = parport_mos7715_read_status, 671b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 672b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .enable_irq = parport_mos7715_enable_irq, 673b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .disable_irq = parport_mos7715_disable_irq, 674b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 675b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .data_forward = parport_mos7715_data_forward, 676b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .data_reverse = parport_mos7715_data_reverse, 677b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 678b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .init_state = parport_mos7715_init_state, 679b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .save_state = parport_mos7715_save_state, 680b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .restore_state = parport_mos7715_restore_state, 681b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 682b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .compat_write_data = parport_mos7715_write_compat, 683b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 684b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .nibble_read_data = parport_ieee1284_read_nibble, 685b69578df7e98659b7d94c905971a6d1025b431adMike Dunn .byte_read_data = parport_ieee1284_read_byte, 686b69578df7e98659b7d94c905971a6d1025b431adMike Dunn}; 687b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 688b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* 689b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * Allocate and initialize parallel port control struct, initialize 690b69578df7e98659b7d94c905971a6d1025b431adMike Dunn * the parallel port hardware device, and register with the parport subsystem. 691b69578df7e98659b7d94c905971a6d1025b431adMike Dunn */ 692b69578df7e98659b7d94c905971a6d1025b431adMike Dunnstatic int mos7715_parport_init(struct usb_serial *serial) 693b69578df7e98659b7d94c905971a6d1025b431adMike Dunn{ 694b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport; 695b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 696b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* allocate and initialize parallel port control struct */ 697b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport = kzalloc(sizeof(struct mos7715_parport), GFP_KERNEL); 698b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (mos_parport == NULL) { 699b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("mos7715_parport_init: kzalloc failed"); 700b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return -ENOMEM; 701b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 702b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->msg_pending = false; 703b69578df7e98659b7d94c905971a6d1025b431adMike Dunn kref_init(&mos_parport->ref_count); 704b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_lock_init(&mos_parport->listlock); 705b69578df7e98659b7d94c905971a6d1025b431adMike Dunn INIT_LIST_HEAD(&mos_parport->active_urbs); 706b69578df7e98659b7d94c905971a6d1025b431adMike Dunn INIT_LIST_HEAD(&mos_parport->deferred_urbs); 707b69578df7e98659b7d94c905971a6d1025b431adMike Dunn usb_set_serial_data(serial, mos_parport); /* hijack private pointer */ 708b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->serial = serial; 709b69578df7e98659b7d94c905971a6d1025b431adMike Dunn tasklet_init(&mos_parport->urb_tasklet, send_deferred_urbs, 710b69578df7e98659b7d94c905971a6d1025b431adMike Dunn (unsigned long) mos_parport); 711b69578df7e98659b7d94c905971a6d1025b431adMike Dunn init_completion(&mos_parport->syncmsg_compl); 712b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 713b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* cycle parallel port reset bit */ 71463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(mos_parport->serial, dummy, PP_REG, (__u8)0x80); 71563b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(mos_parport->serial, dummy, PP_REG, (__u8)0x00); 716b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 717b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* initialize device registers */ 718b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->shadowDCR = DCR_INIT_VAL; 71963b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR); 720b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->shadowECR = ECR_INIT_VAL; 72163b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(mos_parport->serial, dummy, ECR, mos_parport->shadowECR); 722b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 723b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* register with parport core */ 724b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->pp = parport_register_port(0, PARPORT_IRQ_NONE, 725b69578df7e98659b7d94c905971a6d1025b431adMike Dunn PARPORT_DMA_NONE, 726b69578df7e98659b7d94c905971a6d1025b431adMike Dunn &parport_mos7715_ops); 727b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (mos_parport->pp == NULL) { 728b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dev_err(&serial->interface->dev, 729b69578df7e98659b7d94c905971a6d1025b431adMike Dunn "Could not register parport\n"); 730b69578df7e98659b7d94c905971a6d1025b431adMike Dunn kref_put(&mos_parport->ref_count, destroy_mos_parport); 731b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return -EIO; 732b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 733b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->pp->private_data = mos_parport; 734b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->pp->modes = PARPORT_MODE_COMPAT | PARPORT_MODE_PCSPP; 735b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->pp->dev = &serial->interface->dev; 736b69578df7e98659b7d94c905971a6d1025b431adMike Dunn parport_announce_port(mos_parport->pp); 737b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 738b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return 0; 739b69578df7e98659b7d94c905971a6d1025b431adMike Dunn} 740b69578df7e98659b7d94c905971a6d1025b431adMike Dunn#endif /* CONFIG_USB_SERIAL_MOS7715_PARPORT */ 7410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 7420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* 7430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_interrupt_callback 7440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * this is the callback function for when we have received data on the 7450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * interrupt endpoint. 7460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */ 7470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_interrupt_callback(struct urb *urb) 7480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 7490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int result; 7500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int length; 75181105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman int status = urb->status; 752325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum __u8 *data; 7530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman __u8 sp1; 7540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman __u8 sp2; 7550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 75681105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman switch (status) { 7570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case 0: 7580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* success */ 7590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 7600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case -ECONNRESET: 7610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case -ENOENT: 7620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case -ESHUTDOWN: 7630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* this urb is terminated, clean up */ 764441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - urb shutting down with status: %d", __func__, 76581105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman status); 7660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 7670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman default: 768441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - nonzero urb status received: %d", __func__, 76981105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman status); 7700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman goto exit; 7710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 7720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 7730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman length = urb->actual_length; 7740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman data = urb->transfer_buffer; 7750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 7760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Moschip get 4 bytes 7770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Byte 1 IIR Port 1 (port.number is 0) 7780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Byte 2 IIR Port 2 (port.number is 1) 7790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Byte 3 -------------- 7800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Byte 4 FIFO status for both */ 781325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum 782325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum /* the above description is inverted 783325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum * oneukum 2007-03-14 */ 784325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum 785325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum if (unlikely(length != 4)) { 7860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("Wrong data !!!"); 7870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 7880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 7890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 790325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum sp1 = data[3]; 791325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum sp2 = data[2]; 7920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 793325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum if ((sp1 | sp2) & 0x01) { 7940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* No Interrupt Pending in both the ports */ 7950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("No Interrupt !!!"); 7960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } else { 7970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman switch (sp1 & 0x0f) { 7980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case SERIAL_IIR_RLS: 7990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("Serial Port 1: Receiver status error or address " 8000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman "bit detected in 9-bit mode\n"); 8010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 8020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case SERIAL_IIR_CTI: 8030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("Serial Port 1: Receiver time out"); 8040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 8050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case SERIAL_IIR_MS: 806b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* dbg("Serial Port 1: Modem status change"); */ 8070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 8080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 8090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 8100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman switch (sp2 & 0x0f) { 8110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case SERIAL_IIR_RLS: 8120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("Serial Port 2: Receiver status error or address " 8130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman "bit detected in 9-bit mode"); 8140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 8150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case SERIAL_IIR_CTI: 8160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("Serial Port 2: Receiver time out"); 8170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 8180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case SERIAL_IIR_MS: 819b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* dbg("Serial Port 2: Modem status change"); */ 8200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 8210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 8220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 8230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 8240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanexit: 8250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman result = usb_submit_urb(urb, GFP_ATOMIC); 8260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (result) 8270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dev_err(&urb->dev->dev, 8280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman "%s - Error %d submitting control urb\n", 829441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison __func__, result); 8300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 8310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 8320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* 833fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * mos7715_interrupt_callback 834fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * this is the 7715's callback function for when we have received data on 835fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * the interrupt endpoint. 836fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn */ 837fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunnstatic void mos7715_interrupt_callback(struct urb *urb) 838fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn{ 839fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn int result; 840fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn int length; 841fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn int status = urb->status; 842fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn __u8 *data; 843fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn __u8 iir; 844fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn 845fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn switch (status) { 846fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn case 0: 847fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn /* success */ 848fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn break; 849fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn case -ECONNRESET: 850fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn case -ENOENT: 851fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn case -ESHUTDOWN: 852b69578df7e98659b7d94c905971a6d1025b431adMike Dunn case -ENODEV: 853fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn /* this urb is terminated, clean up */ 854fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn dbg("%s - urb shutting down with status: %d", __func__, 855fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn status); 856fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn return; 857fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn default: 858fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn dbg("%s - nonzero urb status received: %d", __func__, 859fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn status); 860fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn goto exit; 861fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn } 862fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn 863fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn length = urb->actual_length; 864fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn data = urb->transfer_buffer; 865fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn 866fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn /* Structure of data from 7715 device: 867fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * Byte 1: IIR serial Port 868fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * Byte 2: unused 869fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * Byte 2: DSR parallel port 870fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * Byte 4: FIFO status for both */ 871fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn 872fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn if (unlikely(length != 4)) { 873fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn dbg("Wrong data !!!"); 874fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn return; 875fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn } 876fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn 877fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn iir = data[0]; 878fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn if (!(iir & 0x01)) { /* serial port interrupt pending */ 879fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn switch (iir & 0x0f) { 880fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn case SERIAL_IIR_RLS: 881fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn dbg("Serial Port: Receiver status error or address " 882fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn "bit detected in 9-bit mode\n"); 883fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn break; 884fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn case SERIAL_IIR_CTI: 885fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn dbg("Serial Port: Receiver time out"); 886fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn break; 887fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn case SERIAL_IIR_MS: 888b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* dbg("Serial Port: Modem status change"); */ 889fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn break; 890fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn } 891fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn } 892fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn 893b69578df7e98659b7d94c905971a6d1025b431adMike Dunn#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT 894b69578df7e98659b7d94c905971a6d1025b431adMike Dunn { /* update local copy of DSR reg */ 895b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct usb_serial_port *port = urb->context; 896b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = port->serial->private; 897b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (unlikely(mos_parport == NULL)) 898b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return; 899b69578df7e98659b7d94c905971a6d1025b431adMike Dunn atomic_set(&mos_parport->shadowDSR, data[2]); 900b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 901b69578df7e98659b7d94c905971a6d1025b431adMike Dunn#endif 902b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 903fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunnexit: 904fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn result = usb_submit_urb(urb, GFP_ATOMIC); 905fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn if (result) 906fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn dev_err(&urb->dev->dev, 907fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn "%s - Error %d submitting control urb\n", 908fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn __func__, result); 909fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn} 910fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn 911fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn/* 9120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_bulk_in_callback 9130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * this is the callback function for when we have received data on the 9140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * bulk in endpoint. 9150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */ 9160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_bulk_in_callback(struct urb *urb) 9170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 91881105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman int retval; 9190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman unsigned char *data ; 9200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_serial_port *port; 9210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct tty_struct *tty; 92281105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman int status = urb->status; 9230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 92481105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman if (status) { 92581105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman dbg("nonzero read bulk status received: %d", status); 9260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 9270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 9280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 929b69578df7e98659b7d94c905971a6d1025b431adMike Dunn port = urb->context; 9300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 931441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("Entering...%s", __func__); 9320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 9330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman data = urb->transfer_buffer; 9340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 9354a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty = tty_port_tty_get(&port->port); 9360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (tty && urb->actual_length) { 9370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman tty_insert_flip_string(tty, data, urb->actual_length); 9380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman tty_flip_buffer_push(tty); 9390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 9404a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty_kref_put(tty); 9410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 9420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (port->read_urb->status != -EINPROGRESS) { 94381105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); 94481105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman if (retval) 94581105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman dbg("usb_submit_urb(read bulk) failed, retval = %d", 94681105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman retval); 9470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 9480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 9490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 9500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* 9510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_bulk_out_data_callback 9520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * this is the callback function for when we have finished sending serial 9530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * data on the bulk out endpoint. 9540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */ 9550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_bulk_out_data_callback(struct urb *urb) 9560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 9570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct moschip_port *mos7720_port; 9580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct tty_struct *tty; 95981105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman int status = urb->status; 9600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 96181105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman if (status) { 96281105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman dbg("nonzero write bulk status received:%d", status); 9630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 9640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 9650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 9660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port = urb->context; 9670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (!mos7720_port) { 9680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("NULL mos7720_port pointer"); 9690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return ; 9700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 9710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 9724a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty = tty_port_tty_get(&mos7720_port->port->port); 9730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 974b963a8441cb95999c97bea379607071a869c65f0Jiri Slaby if (tty && mos7720_port->open) 975b963a8441cb95999c97bea379607071a869c65f0Jiri Slaby tty_wakeup(tty); 9764a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty_kref_put(tty); 9770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 9780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 9790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* 980fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * mos77xx_probe 981fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * this function installs the appropriate read interrupt endpoint callback 982fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * depending on whether the device is a 7720 or 7715, thus avoiding costly 983fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * run-time checks in the high-frequency callback routine itself. 984fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn */ 985fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunnstatic int mos77xx_probe(struct usb_serial *serial, 986fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn const struct usb_device_id *id) 987fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn{ 988fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn if (id->idProduct == MOSCHIP_DEVICE_ID_7715) 989fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn moschip7720_2port_driver.read_int_callback = 990fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn mos7715_interrupt_callback; 991fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn else 992fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn moschip7720_2port_driver.read_int_callback = 993fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn mos7720_interrupt_callback; 994fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn 995fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn return 0; 996fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn} 997fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn 998fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunnstatic int mos77xx_calc_num_ports(struct usb_serial *serial) 999fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn{ 1000fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); 1001fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn if (product == MOSCHIP_DEVICE_ID_7715) 1002fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn return 1; 1003fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn 1004fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn return 2; 1005fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn} 1006fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn 1007a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) 10080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 10090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_serial *serial; 10100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct urb *urb; 10110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct moschip_port *mos7720_port; 10120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int response; 10130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int port_number; 101463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn __u8 data; 1015fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum int allocated_urbs = 0; 10160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int j; 10170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 10180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman serial = port->serial; 10190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 10200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port = usb_get_serial_port_data(port); 10210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) 10220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -ENODEV; 10230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 10240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman usb_clear_halt(serial->dev, port->write_urb->pipe); 10250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman usb_clear_halt(serial->dev, port->read_urb->pipe); 10260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 10270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Initialising the write urb pool */ 10280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman for (j = 0; j < NUM_URBS; ++j) { 10294da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox urb = usb_alloc_urb(0, GFP_KERNEL); 10300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port->write_urb_pool[j] = urb; 10310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 10320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (urb == NULL) { 1033194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, "No more urbs???\n"); 10340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman continue; 10350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 10360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 10370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, 10380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman GFP_KERNEL); 10390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (!urb->transfer_buffer) { 1040194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, 1041194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman "%s-out of memory for urb buffers.\n", 1042194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman __func__); 1043fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum usb_free_urb(mos7720_port->write_urb_pool[j]); 1044fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum mos7720_port->write_urb_pool[j] = NULL; 10450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman continue; 10460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 1047fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum allocated_urbs++; 10480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 10490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1050fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum if (!allocated_urbs) 1051fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum return -ENOMEM; 1052fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum 10530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Initialize MCS7720 -- Write Init values to corresponding Registers 10540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 10550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Register Index 10562f9ea55c98bd03265e1c3eb114718eb2974df4cbKees Schoenmakers * 0 : THR/RHR 10570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 1 : IER 10580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 2 : FCR 10590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 3 : LCR 10600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 4 : MCR 10612f9ea55c98bd03265e1c3eb114718eb2974df4cbKees Schoenmakers * 5 : LSR 10622f9ea55c98bd03265e1c3eb114718eb2974df4cbKees Schoenmakers * 6 : MSR 10632f9ea55c98bd03265e1c3eb114718eb2974df4cbKees Schoenmakers * 7 : SPR 10640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 10650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 0x08 : SP1/2 Control Reg 10660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */ 10670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman port_number = port->number - port->serial->minor; 106863b917678fe6d63e633462b5be5a309511bcf3caMike Dunn read_mos_reg(serial, port_number, LSR, &data); 106963b917678fe6d63e633462b5be5a309511bcf3caMike Dunn 1070759f3634267a67ac90f3fa7fc06510dfd43b4e45Joe Perches dbg("SS::%p LSR:%x", mos7720_port, data); 10710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 10720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("Check:Sending Command .........."); 10730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 107463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, dummy, SP1_REG, 0x02); 107563b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, dummy, SP2_REG, 0x02); 10760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 107763b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, IER, 0x00); 107863b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, FCR, 0x00); 10790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 108063b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, FCR, 0xcf); 108163b917678fe6d63e633462b5be5a309511bcf3caMike Dunn mos7720_port->shadowLCR = 0x03; 108263b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); 108363b917678fe6d63e633462b5be5a309511bcf3caMike Dunn mos7720_port->shadowMCR = 0x0b; 108463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); 10850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 108663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, SP_CONTROL_REG, 0x00); 108763b917678fe6d63e633462b5be5a309511bcf3caMike Dunn read_mos_reg(serial, dummy, SP_CONTROL_REG, &data); 10880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman data = data | (port->number - port->serial->minor + 1); 108963b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, dummy, SP_CONTROL_REG, data); 109063b917678fe6d63e633462b5be5a309511bcf3caMike Dunn mos7720_port->shadowLCR = 0x83; 109163b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); 109263b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, THR, 0x0c); 109363b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, IER, 0x00); 109463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn mos7720_port->shadowLCR = 0x03; 109563b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); 109663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, IER, 0x0c); 10970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 10980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman response = usb_submit_urb(port->read_urb, GFP_KERNEL); 10990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (response) 11004da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox dev_err(&port->dev, "%s - Error %d submitting read urb\n", 11014da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox __func__, response); 11020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 11030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* initialize our icount structure */ 11040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount)); 11050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 11060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* initialize our port settings */ 11070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */ 11080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 11090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* send a open port command */ 11100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port->open = 1; 11110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 11120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return 0; 11130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 11140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 11150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* 11160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_chars_in_buffer 11170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * this function is called by the tty driver when it wants to know how many 11180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * bytes of data we currently have outstanding in the port (data that has 11190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * been written, but hasn't made it out the port yet) 11200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * If successful, we return the number of bytes left to be written in the 11210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * system, 11220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Otherwise we return a negative error number. 11230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */ 112495da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int mos7720_chars_in_buffer(struct tty_struct *tty) 11250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 112695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 11270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int i; 11280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int chars = 0; 11290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct moschip_port *mos7720_port; 11300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1131441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s:entering ...........", __func__); 11320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 11330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port = usb_get_serial_port_data(port); 11340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) { 1135441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s:leaving ...........", __func__); 113623198fda7182969b619613a555f8645fdc3dc334Alan Cox return 0; 11370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 11380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 11390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman for (i = 0; i < NUM_URBS; ++i) { 11404da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox if (mos7720_port->write_urb_pool[i] && 11414da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox mos7720_port->write_urb_pool[i]->status == -EINPROGRESS) 11420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman chars += URB_TRANSFER_BUFFER_SIZE; 11430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 1144441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - returns %d", __func__, chars); 11450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return chars; 11460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 11470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1148335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void mos7720_close(struct usb_serial_port *port) 11490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 11500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_serial *serial; 11510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct moschip_port *mos7720_port; 11520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int j; 11530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 11540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("mos7720_close:entering..."); 11550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 11560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman serial = port->serial; 11570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 11580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port = usb_get_serial_port_data(port); 11590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) 11600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 11610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 11620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman for (j = 0; j < NUM_URBS; ++j) 11630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman usb_kill_urb(mos7720_port->write_urb_pool[j]); 11640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 11650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Freeing Write URBs */ 11660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman for (j = 0; j < NUM_URBS; ++j) { 11670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port->write_urb_pool[j]) { 11680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman kfree(mos7720_port->write_urb_pool[j]->transfer_buffer); 11690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman usb_free_urb(mos7720_port->write_urb_pool[j]); 11700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 11710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 11720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 11730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* While closing port, shutdown all bulk read, write * 1174a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum * and interrupt read if they exists, otherwise nop */ 1175a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum dbg("Shutdown bulk write"); 1176a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum usb_kill_urb(port->write_urb); 1177a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum dbg("Shutdown bulk read"); 1178a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum usb_kill_urb(port->read_urb); 1179a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum 1180a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum mutex_lock(&serial->disc_mutex); 1181a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum /* these commands must not be issued if the device has 1182a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum * been disconnected */ 1183a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum if (!serial->disconnected) { 118463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port->number - port->serial->minor, 118563b917678fe6d63e633462b5be5a309511bcf3caMike Dunn MCR, 0x00); 118663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port->number - port->serial->minor, 118763b917678fe6d63e633462b5be5a309511bcf3caMike Dunn IER, 0x00); 11880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 1189a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum mutex_unlock(&serial->disc_mutex); 11900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port->open = 0; 11910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1192441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("Leaving %s", __func__); 11930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 11940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 119595da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void mos7720_break(struct tty_struct *tty, int break_state) 11960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 119795da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 11984da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox unsigned char data; 11990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_serial *serial; 12000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct moschip_port *mos7720_port; 12010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1202441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("Entering %s", __func__); 12030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 12040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman serial = port->serial; 12050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 12060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port = usb_get_serial_port_data(port); 12070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) 12080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 12090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 12100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (break_state == -1) 12110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman data = mos7720_port->shadowLCR | UART_LCR_SBC; 12120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman else 12130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman data = mos7720_port->shadowLCR & ~UART_LCR_SBC; 12140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 12150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port->shadowLCR = data; 121663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port->number - port->serial->minor, 121763b917678fe6d63e633462b5be5a309511bcf3caMike Dunn LCR, mos7720_port->shadowLCR); 12180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 12190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 12200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* 12210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_write_room 12220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * this function is called by the tty driver when it wants to know how many 12230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * bytes of data we can accept for a specific port. 12240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * If successful, we return the amount of room that we have for this port 12250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Otherwise we return a negative error number. 12260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */ 122795da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int mos7720_write_room(struct tty_struct *tty) 12280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 122995da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 12300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct moschip_port *mos7720_port; 12310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int room = 0; 12320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int i; 12330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1234441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s:entering ...........", __func__); 12350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 12360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port = usb_get_serial_port_data(port); 12370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) { 1238441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s:leaving ...........", __func__); 12390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -ENODEV; 12400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 12410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1242a5b6f60c5a30c494017c7a2d11c4067f90d3d0dfAlan Cox /* FIXME: Locking */ 12430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman for (i = 0; i < NUM_URBS; ++i) { 12444da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox if (mos7720_port->write_urb_pool[i] && 12454da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) 12460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman room += URB_TRANSFER_BUFFER_SIZE; 12470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 12480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1249441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - returns %d", __func__, room); 12500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return room; 12510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 12520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 125395da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port, 125495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox const unsigned char *data, int count) 12550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 12560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int status; 12570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int i; 12580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int bytes_sent = 0; 12590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int transfer_size; 12600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 12610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct moschip_port *mos7720_port; 12620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_serial *serial; 12630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct urb *urb; 12640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman const unsigned char *current_position = data; 12650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1266441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s:entering ...........", __func__); 12670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 12680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman serial = port->serial; 12690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 12700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port = usb_get_serial_port_data(port); 12710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) { 12720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("mos7720_port is NULL"); 12730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -ENODEV; 12740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 12750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 12760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* try to find a free urb in the list */ 12770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman urb = NULL; 12780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 12790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman for (i = 0; i < NUM_URBS; ++i) { 12804da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox if (mos7720_port->write_urb_pool[i] && 12814da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) { 12820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman urb = mos7720_port->write_urb_pool[i]; 12834da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox dbg("URB:%d", i); 12840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 12850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 12860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 12870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 12880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (urb == NULL) { 1289441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - no more free urbs", __func__); 12900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman goto exit; 12910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 12920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 12930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (urb->transfer_buffer == NULL) { 12940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, 12950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman GFP_KERNEL); 12960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (urb->transfer_buffer == NULL) { 129722a416c4e0f2179b57028e084ac0ed2c110333bdJohan Hovold dev_err_console(port, "%s no more kernel memory...\n", 1298194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman __func__); 12990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman goto exit; 13000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 13010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 13024da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE); 13030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 13040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman memcpy(urb->transfer_buffer, current_position, transfer_size); 1305441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison usb_serial_debug_data(debug, &port->dev, __func__, transfer_size, 13060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman urb->transfer_buffer); 13070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 13080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* fill urb with data and submit */ 13090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman usb_fill_bulk_urb(urb, serial->dev, 13100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman usb_sndbulkpipe(serial->dev, 13114da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox port->bulk_out_endpointAddress), 13120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman urb->transfer_buffer, transfer_size, 13130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_bulk_out_data_callback, mos7720_port); 13140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 13150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* send it down the pipe */ 13164da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox status = usb_submit_urb(urb, GFP_ATOMIC); 13170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (status) { 131822a416c4e0f2179b57028e084ac0ed2c110333bdJohan Hovold dev_err_console(port, "%s - usb_submit_urb(write bulk) failed " 1319194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman "with status = %d\n", __func__, status); 13200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman bytes_sent = status; 13210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman goto exit; 13220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 13230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman bytes_sent = transfer_size; 13240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 13250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanexit: 13260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return bytes_sent; 13270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 13280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 132995da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void mos7720_throttle(struct tty_struct *tty) 13300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 133195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 13320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct moschip_port *mos7720_port; 13330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int status; 13340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1335759f3634267a67ac90f3fa7fc06510dfd43b4e45Joe Perches dbg("%s- port %d", __func__, port->number); 13360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 13370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port = usb_get_serial_port_data(port); 13380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 13390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) 13400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 13410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 13420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (!mos7720_port->open) { 13430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("port not opened"); 13440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 13450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 13460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1347441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s: Entering ..........", __func__); 13480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 13490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* if we are implementing XON/XOFF, send the stop character */ 13500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (I_IXOFF(tty)) { 13510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman unsigned char stop_char = STOP_CHAR(tty); 135295da310e66ee8090119596c70ca8432e57f9a97fAlan Cox status = mos7720_write(tty, port, &stop_char, 1); 13530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (status <= 0) 13540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 13550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 13560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 13570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* if we are implementing RTS/CTS, toggle that line */ 13580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (tty->termios->c_cflag & CRTSCTS) { 13590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port->shadowMCR &= ~UART_MCR_RTS; 136063b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(port->serial, port->number - port->serial->minor, 136163b917678fe6d63e633462b5be5a309511bcf3caMike Dunn MCR, mos7720_port->shadowMCR); 13620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (status != 0) 13630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 13640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 13650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 13660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 136795da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void mos7720_unthrottle(struct tty_struct *tty) 13680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 136995da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 13700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct moschip_port *mos7720_port = usb_get_serial_port_data(port); 137195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox int status; 13720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 13730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) 13740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 13750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 13760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (!mos7720_port->open) { 1377441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port not opened", __func__); 13780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 13790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 13800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1381441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s: Entering ..........", __func__); 13820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 13830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* if we are implementing XON/XOFF, send the start character */ 13840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (I_IXOFF(tty)) { 13850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman unsigned char start_char = START_CHAR(tty); 138695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox status = mos7720_write(tty, port, &start_char, 1); 13870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (status <= 0) 13880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 13890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 13900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 13910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* if we are implementing RTS/CTS, toggle that line */ 13920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (tty->termios->c_cflag & CRTSCTS) { 13930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port->shadowMCR |= UART_MCR_RTS; 139463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(port->serial, port->number - port->serial->minor, 139563b917678fe6d63e633462b5be5a309511bcf3caMike Dunn MCR, mos7720_port->shadowMCR); 13960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (status != 0) 13970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 13980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 13990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 14000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1401b69578df7e98659b7d94c905971a6d1025b431adMike Dunn/* FIXME: this function does not work */ 14020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int set_higher_rates(struct moschip_port *mos7720_port, 14030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman unsigned int baud) 14040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 14050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_serial_port *port; 14060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_serial *serial; 14070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int port_number; 140863b917678fe6d63e633462b5be5a309511bcf3caMike Dunn enum mos_regs sp_reg; 14090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) 14100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -EINVAL; 14110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 14120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman port = mos7720_port->port; 14130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman serial = port->serial; 14140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 14154da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox /*********************************************** 14164da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox * Init Sequence for higher rates 14174da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox ***********************************************/ 14180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("Sending Setting Commands .........."); 14190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman port_number = port->number - port->serial->minor; 14200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 142163b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, IER, 0x00); 142263b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, FCR, 0x00); 142363b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, FCR, 0xcf); 142463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn mos7720_port->shadowMCR = 0x0b; 142563b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); 142663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x00); 14270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 14284da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox /*********************************************** 14294da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox * Set for higher rates * 14304da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox ***********************************************/ 1431b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* writing baud rate verbatum into uart clock field clearly not right */ 143263b917678fe6d63e633462b5be5a309511bcf3caMike Dunn if (port_number == 0) 143363b917678fe6d63e633462b5be5a309511bcf3caMike Dunn sp_reg = SP1_REG; 143463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn else 143563b917678fe6d63e633462b5be5a309511bcf3caMike Dunn sp_reg = SP2_REG; 143663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, dummy, sp_reg, baud * 0x10); 143763b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x03); 143863b917678fe6d63e633462b5be5a309511bcf3caMike Dunn mos7720_port->shadowMCR = 0x2b; 143963b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); 14400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 14414da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox /*********************************************** 14424da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox * Set DLL/DLM 14434da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox ***********************************************/ 144463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn mos7720_port->shadowLCR = mos7720_port->shadowLCR | UART_LCR_DLAB; 144563b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); 144663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, DLL, 0x01); 144763b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, DLM, 0x00); 144863b917678fe6d63e633462b5be5a309511bcf3caMike Dunn mos7720_port->shadowLCR = mos7720_port->shadowLCR & ~UART_LCR_DLAB; 144963b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); 14500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 14510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return 0; 14520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 14530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 14540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* baud rate information */ 14554da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Coxstruct divisor_table_entry { 14560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman __u32 baudrate; 14570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman __u16 divisor; 14580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}; 14590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 14600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* Define table of divisors for moschip 7720 hardware * 14610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * These assume a 3.6864MHz crystal, the standard /16, and * 14620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * MCR.7 = 0. */ 14630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic struct divisor_table_entry divisor_table[] = { 14640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 50, 2304}, 14650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 110, 1047}, /* 2094.545455 => 230450 => .0217 % over */ 14660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 134, 857}, /* 1713.011152 => 230398.5 => .00065% under */ 14670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 150, 768}, 14680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 300, 384}, 14690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 600, 192}, 14700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 1200, 96}, 14710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 1800, 64}, 14720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 2400, 48}, 14730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 4800, 24}, 14740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 7200, 16}, 14750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 9600, 12}, 14760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 19200, 6}, 14770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 38400, 3}, 14780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 57600, 2}, 14790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman { 115200, 1}, 14800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}; 14810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 14820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/***************************************************************************** 14830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * calc_baud_rate_divisor 14840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * this function calculates the proper baud rate divisor for the specified 14850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * baud rate. 14860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *****************************************************************************/ 14870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int calc_baud_rate_divisor(int baudrate, int *divisor) 14880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 14890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int i; 14900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman __u16 custom; 14910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman __u16 round1; 14920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman __u16 round; 14930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 14940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1495441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - %d", __func__, baudrate); 14960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 14970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman for (i = 0; i < ARRAY_SIZE(divisor_table); i++) { 14980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (divisor_table[i].baudrate == baudrate) { 14990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *divisor = divisor_table[i].divisor; 15000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return 0; 15010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 15020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 15030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15044da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox /* After trying for all the standard baud rates * 15054da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox * Try calculating the divisor for this baud rate */ 15060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (baudrate > 75 && baudrate < 230400) { 15070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* get the divisor */ 15080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman custom = (__u16)(230400L / baudrate); 15090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Check for round off */ 15110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman round1 = (__u16)(2304000L / baudrate); 15120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman round = (__u16)(round1 - (custom * 10)); 15130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (round > 4) 15140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman custom++; 15150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *divisor = custom; 15160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15174da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox dbg("Baud %d = %d", baudrate, custom); 15180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return 0; 15190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 15200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("Baud calculation Failed..."); 15220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -EINVAL; 15230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 15240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* 15260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * send_cmd_write_baud_rate 15270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * this function sends the proper command to change the baud rate of the 15280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * specified port. 15290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */ 15300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, 15310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int baudrate) 15320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 15330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_serial_port *port; 15340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_serial *serial; 15350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int divisor; 15360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int status; 15370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman unsigned char number; 15380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) 15400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -1; 15410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman port = mos7720_port->port; 15430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman serial = port->serial; 15440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1545441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s: Entering ..........", __func__); 15460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman number = port->number - port->serial->minor; 1548441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port = %d, baud = %d", __func__, port->number, baudrate); 15490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15504da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox /* Calculate the Divisor */ 15510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman status = calc_baud_rate_divisor(baudrate, &divisor); 15520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (status) { 1553194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, "%s - bad baud rate\n", __func__); 15540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return status; 15550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 15560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15574da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox /* Enable access to divisor latch */ 155863b917678fe6d63e633462b5be5a309511bcf3caMike Dunn mos7720_port->shadowLCR = mos7720_port->shadowLCR | UART_LCR_DLAB; 155963b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, number, LCR, mos7720_port->shadowLCR); 15600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Write the divisor */ 156263b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, number, DLL, (__u8)(divisor & 0xff)); 156363b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, number, DLM, (__u8)((divisor & 0xff00) >> 8)); 15640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15654da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox /* Disable access to divisor latch */ 156663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn mos7720_port->shadowLCR = mos7720_port->shadowLCR & ~UART_LCR_DLAB; 156763b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, number, LCR, mos7720_port->shadowLCR); 15680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return status; 15700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 15710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* 15730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * change_port_settings 15740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * This routine is called to set the UART on the device to match 15750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * the specified new settings. 15760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */ 157795da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void change_port_settings(struct tty_struct *tty, 157895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct moschip_port *mos7720_port, 1579606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios *old_termios) 15800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 15810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_serial_port *port; 15820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_serial *serial; 15830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int baud; 15840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman unsigned cflag; 15850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman unsigned iflag; 15860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman __u8 mask = 0xff; 15870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman __u8 lData; 15880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman __u8 lParity; 15890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman __u8 lStop; 15900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int status; 15910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int port_number; 15920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) 15940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return ; 15950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 15960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman port = mos7720_port->port; 15970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman serial = port->serial; 15980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman port_number = port->number - port->serial->minor; 15990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1600441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 16010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (!mos7720_port->open) { 1603441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port not opened", __func__); 16040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 16050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 16060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1607441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s: Entering ..........", __func__); 16080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman lData = UART_LCR_WLEN8; 16100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman lStop = 0x00; /* 1 stop bit */ 16110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman lParity = 0x00; /* No parity */ 16120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman cflag = tty->termios->c_cflag; 16140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman iflag = tty->termios->c_iflag; 16150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Change the number of bits */ 16170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman switch (cflag & CSIZE) { 16180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case CS5: 16190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman lData = UART_LCR_WLEN5; 16200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mask = 0x1f; 16210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 16220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case CS6: 16240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman lData = UART_LCR_WLEN6; 16250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mask = 0x3f; 16260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 16270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case CS7: 16290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman lData = UART_LCR_WLEN7; 16300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mask = 0x7f; 16310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 16320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman default: 16330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case CS8: 16340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman lData = UART_LCR_WLEN8; 16350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 16360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 16370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Change the Parity bit */ 16390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (cflag & PARENB) { 16400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (cflag & PARODD) { 16410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman lParity = UART_LCR_PARITY; 1642441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - parity = odd", __func__); 16430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } else { 16440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman lParity = (UART_LCR_EPAR | UART_LCR_PARITY); 1645441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - parity = even", __func__); 16460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 16470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } else { 1649441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - parity = none", __func__); 16500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 16510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (cflag & CMSPAR) 16530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman lParity = lParity | 0x20; 16540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Change the Stop bit */ 16560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (cflag & CSTOPB) { 16570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman lStop = UART_LCR_STOP; 1658441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - stop bits = 2", __func__); 16590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } else { 16600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman lStop = 0x00; 1661441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - stop bits = 1", __func__); 16620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 16630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */ 16650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */ 16660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define LCR_PAR_MASK 0x38 /* Mask for parity field */ 16670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Update the LCR with the correct value */ 16694da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox mos7720_port->shadowLCR &= 167063b917678fe6d63e633462b5be5a309511bcf3caMike Dunn ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); 16710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port->shadowLCR |= (lData | lParity | lStop); 16720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Disable Interrupts */ 167563b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, IER, 0x00); 167663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, FCR, 0x00); 167763b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, FCR, 0xcf); 16780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Send the updated LCR value to the mos7720 */ 168063b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); 168163b917678fe6d63e633462b5be5a309511bcf3caMike Dunn mos7720_port->shadowMCR = 0x0b; 168263b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); 16830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* set up the MCR register and send it to the mos7720 */ 16850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port->shadowMCR = UART_MCR_OUT2; 16860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (cflag & CBAUD) 16870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port->shadowMCR |= (UART_MCR_DTR | UART_MCR_RTS); 16880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 16890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (cflag & CRTSCTS) { 16900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port->shadowMCR |= (UART_MCR_XONANY); 16914da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox /* To set hardware flow control to the specified * 16924da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox * serial port, in SP1/2_CONTROL_REG */ 169363b917678fe6d63e633462b5be5a309511bcf3caMike Dunn if (port->number) 169463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x01); 169563b917678fe6d63e633462b5be5a309511bcf3caMike Dunn else 169663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x02); 169763b917678fe6d63e633462b5be5a309511bcf3caMike Dunn 169863b917678fe6d63e633462b5be5a309511bcf3caMike Dunn } else 16990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port->shadowMCR &= ~(UART_MCR_XONANY); 17000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 170163b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); 17020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 17030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Determine divisor based on baud rate */ 17040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman baud = tty_get_baud_rate(tty); 17050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (!baud) { 17060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* pick a default, any default... */ 17070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("Picked default baud..."); 17080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman baud = 9600; 17090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 17100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 17110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (baud >= 230400) { 17120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman set_higher_rates(mos7720_port, baud); 17130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Enable Interrupts */ 171463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, IER, 0x0c); 17150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 17160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 17170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1718441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - baud rate = %d", __func__, baud); 17190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman status = send_cmd_write_baud_rate(mos7720_port, baud); 172065d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox /* FIXME: needs to write actual resulting baud back not just 172165d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox blindly do so */ 172265d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox if (cflag & CBAUD) 172365d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox tty_encode_baud_rate(tty, baud, baud); 17240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Enable Interrupts */ 172563b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(serial, port_number, IER, 0x0c); 17260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 17270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (port->read_urb->status != -EINPROGRESS) { 17280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman status = usb_submit_urb(port->read_urb, GFP_ATOMIC); 17290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (status) 17300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("usb_submit_urb(read bulk) failed, status = %d", 17310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman status); 17320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 17330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 17340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 17350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* 17360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_set_termios 17370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * this function is called by the tty driver when it wants to change the 17380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * termios structure. 17390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */ 174095da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void mos7720_set_termios(struct tty_struct *tty, 174195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port, struct ktermios *old_termios) 17420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 17430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int status; 17440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman unsigned int cflag; 17450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_serial *serial; 17460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct moschip_port *mos7720_port; 17470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 17480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman serial = port->serial; 17490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 17500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port = usb_get_serial_port_data(port); 17510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 17520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) 17530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 17540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 17550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (!mos7720_port->open) { 1756441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port not opened", __func__); 17570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return; 17580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 17590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1760b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dbg("%s\n", "setting termios - ASPIRE"); 17610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 17620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman cflag = tty->termios->c_cflag; 17630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1764441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - cflag %08x iflag %08x", __func__, 17650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman tty->termios->c_cflag, 17660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman RELEVANT_IFLAG(tty->termios->c_iflag)); 17670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1768441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - old cflag %08x old iflag %08x", __func__, 176965d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox old_termios->c_cflag, 177065d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox RELEVANT_IFLAG(old_termios->c_iflag)); 17710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1772441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 17730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 17740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* change the port settings to the new ones specified */ 177595da310e66ee8090119596c70ca8432e57f9a97fAlan Cox change_port_settings(tty, mos7720_port, old_termios); 17760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 17774da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox if (port->read_urb->status != -EINPROGRESS) { 17780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman status = usb_submit_urb(port->read_urb, GFP_ATOMIC); 17790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (status) 17800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("usb_submit_urb(read bulk) failed, status = %d", 17810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman status); 17820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 17830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 17840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 17850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* 17860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * get_lsr_info - get line status register info 17870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 17880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Purpose: Let user call ioctl() to get info when the UART physically 17890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * is emptied. On bus types like RS485, the transmitter must 17900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * release the bus after transmitting. This must be done when 17910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * the transmit shift register is empty, not be done when the 17920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * transmit holding register is empty. This functionality 17930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * allows an RS485 driver to be written in user space. 17940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */ 17954da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Coxstatic int get_lsr_info(struct tty_struct *tty, 17964da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox struct moschip_port *mos7720_port, unsigned int __user *value) 17970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 17982f9ea55c98bd03265e1c3eb114718eb2974df4cbKees Schoenmakers struct usb_serial_port *port = tty->driver_data; 17990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman unsigned int result = 0; 18002f9ea55c98bd03265e1c3eb114718eb2974df4cbKees Schoenmakers unsigned char data = 0; 18012f9ea55c98bd03265e1c3eb114718eb2974df4cbKees Schoenmakers int port_number = port->number - port->serial->minor; 18022f9ea55c98bd03265e1c3eb114718eb2974df4cbKees Schoenmakers int count; 18030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 180495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox count = mos7720_chars_in_buffer(tty); 18050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (count == 0) { 180663b917678fe6d63e633462b5be5a309511bcf3caMike Dunn read_mos_reg(port->serial, port_number, LSR, &data); 18072f9ea55c98bd03265e1c3eb114718eb2974df4cbKees Schoenmakers if ((data & (UART_LSR_TEMT | UART_LSR_THRE)) 18082f9ea55c98bd03265e1c3eb114718eb2974df4cbKees Schoenmakers == (UART_LSR_TEMT | UART_LSR_THRE)) { 18092f9ea55c98bd03265e1c3eb114718eb2974df4cbKees Schoenmakers dbg("%s -- Empty", __func__); 18102f9ea55c98bd03265e1c3eb114718eb2974df4cbKees Schoenmakers result = TIOCSER_TEMT; 18112f9ea55c98bd03265e1c3eb114718eb2974df4cbKees Schoenmakers } 18120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 18130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (copy_to_user(value, &result, sizeof(int))) 18140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -EFAULT; 18150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return 0; 18160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 18170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 181860b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int mos7720_tiocmget(struct tty_struct *tty) 18190f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers{ 18200f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers struct usb_serial_port *port = tty->driver_data; 18210f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers struct moschip_port *mos7720_port = usb_get_serial_port_data(port); 18220f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers unsigned int result = 0; 18230f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers unsigned int mcr ; 18240f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers unsigned int msr ; 18250f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers 18260f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers dbg("%s - port %d", __func__, port->number); 18270f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers 18280f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers mcr = mos7720_port->shadowMCR; 18290f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers msr = mos7720_port->shadowMSR; 18300f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers 18310f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR : 0) /* 0x002 */ 18320f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers | ((mcr & UART_MCR_RTS) ? TIOCM_RTS : 0) /* 0x004 */ 18330f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers | ((msr & UART_MSR_CTS) ? TIOCM_CTS : 0) /* 0x020 */ 18340f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers | ((msr & UART_MSR_DCD) ? TIOCM_CAR : 0) /* 0x040 */ 18350f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers | ((msr & UART_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */ 18360f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers | ((msr & UART_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */ 18370f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers 18380f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers dbg("%s -- %x", __func__, result); 18390f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers 18400f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers return result; 18410f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers} 18420f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers 184320b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int mos7720_tiocmset(struct tty_struct *tty, 184463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn unsigned int set, unsigned int clear) 18450f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers{ 18460f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers struct usb_serial_port *port = tty->driver_data; 18470f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers struct moschip_port *mos7720_port = usb_get_serial_port_data(port); 18480f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers unsigned int mcr ; 18490f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers dbg("%s - port %d", __func__, port->number); 185060b33c133ca0b7c0b6072c87234b63fee6e80558Alan Cox dbg("he was at tiocmset"); 18510f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers 18520f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers mcr = mos7720_port->shadowMCR; 18530f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers 18540f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers if (set & TIOCM_RTS) 18550f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers mcr |= UART_MCR_RTS; 18560f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers if (set & TIOCM_DTR) 18570f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers mcr |= UART_MCR_DTR; 18580f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers if (set & TIOCM_LOOP) 18590f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers mcr |= UART_MCR_LOOP; 18600f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers 18610f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers if (clear & TIOCM_RTS) 18620f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers mcr &= ~UART_MCR_RTS; 18630f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers if (clear & TIOCM_DTR) 18640f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers mcr &= ~UART_MCR_DTR; 18650f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers if (clear & TIOCM_LOOP) 18660f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers mcr &= ~UART_MCR_LOOP; 18670f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers 18680f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers mos7720_port->shadowMCR = mcr; 186963b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(port->serial, port->number - port->serial->minor, 187063b917678fe6d63e633462b5be5a309511bcf3caMike Dunn MCR, mos7720_port->shadowMCR); 18710f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers 18720f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers return 0; 18730f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers} 18740f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers 18750bca1b913affbd7e2fdaffee62a499659a466eb5Alan Coxstatic int mos7720_get_icount(struct tty_struct *tty, 18760bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox struct serial_icounter_struct *icount) 18770bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox{ 18780bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox struct usb_serial_port *port = tty->driver_data; 18790bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox struct moschip_port *mos7720_port; 18800bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox struct async_icount cnow; 18810bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox 18820bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox mos7720_port = usb_get_serial_port_data(port); 18830bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox cnow = mos7720_port->icount; 18840bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox 18850bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->cts = cnow.cts; 18860bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->dsr = cnow.dsr; 18870bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->rng = cnow.rng; 18880bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->dcd = cnow.dcd; 18890bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->rx = cnow.rx; 18900bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->tx = cnow.tx; 18910bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->frame = cnow.frame; 18920bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->overrun = cnow.overrun; 18930bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->parity = cnow.parity; 18940bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->brk = cnow.brk; 18950bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->buf_overrun = cnow.buf_overrun; 18960bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox 18970bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__, 18980bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox port->number, icount->rx, icount->tx); 18990bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox return 0; 19000bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox} 19010bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox 19020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, 19030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman unsigned int __user *value) 19040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 19050bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox unsigned int mcr; 19060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman unsigned int arg; 19070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_serial_port *port; 19090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) 19110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -1; 19120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19134da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox port = (struct usb_serial_port *)mos7720_port->port; 19140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mcr = mos7720_port->shadowMCR; 19150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (copy_from_user(&arg, value, sizeof(int))) 19170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -EFAULT; 19180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman switch (cmd) { 19200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case TIOCMBIS: 19210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (arg & TIOCM_RTS) 19220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mcr |= UART_MCR_RTS; 19230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (arg & TIOCM_DTR) 19240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mcr |= UART_MCR_RTS; 19250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (arg & TIOCM_LOOP) 19260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mcr |= UART_MCR_LOOP; 19270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 19280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case TIOCMBIC: 19300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (arg & TIOCM_RTS) 19310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mcr &= ~UART_MCR_RTS; 19320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (arg & TIOCM_DTR) 19330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mcr &= ~UART_MCR_RTS; 19340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (arg & TIOCM_LOOP) 19350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mcr &= ~UART_MCR_LOOP; 19360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 19370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 19390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port->shadowMCR = mcr; 194163b917678fe6d63e633462b5be5a309511bcf3caMike Dunn write_mos_reg(port->serial, port->number - port->serial->minor, 194263b917678fe6d63e633462b5be5a309511bcf3caMike Dunn MCR, mos7720_port->shadowMCR); 19430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return 0; 19450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 19460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int get_serial_info(struct moschip_port *mos7720_port, 19480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct serial_struct __user *retinfo) 19490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 19500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct serial_struct tmp; 19510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (!retinfo) 19530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -EFAULT; 19540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman memset(&tmp, 0, sizeof(tmp)); 19560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman tmp.type = PORT_16550A; 19580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman tmp.line = mos7720_port->port->serial->minor; 19590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman tmp.port = mos7720_port->port->number; 19600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman tmp.irq = 0; 19610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; 19624da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; 19630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman tmp.baud_base = 9600; 19640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman tmp.close_delay = 5*HZ; 19650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman tmp.closing_wait = 30*HZ; 19660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) 19680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -EFAULT; 19690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return 0; 19700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 19710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 197200a0d0d65b61241a718d0aee96f46b9a2d93bf26Alan Coxstatic int mos7720_ioctl(struct tty_struct *tty, 19730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman unsigned int cmd, unsigned long arg) 19740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 197595da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 19760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct moschip_port *mos7720_port; 19770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct async_icount cnow; 19780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct async_icount cprev; 19790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port = usb_get_serial_port_data(port); 19810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) 19820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -ENODEV; 19830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 1984441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); 19850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 19860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman switch (cmd) { 19870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case TIOCSERGETLSR: 1988441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s (%d) TIOCSERGETLSR", __func__, port->number); 19894da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox return get_lsr_info(tty, mos7720_port, 19904da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox (unsigned int __user *)arg); 19910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 199295da310e66ee8090119596c70ca8432e57f9a97fAlan Cox /* FIXME: These should be using the mode methods */ 19930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case TIOCMBIS: 19940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case TIOCMBIC: 19954da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", 19964da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox __func__, port->number); 19970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return set_modem_info(mos7720_port, cmd, 19980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman (unsigned int __user *)arg); 19990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 20000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case TIOCGSERIAL: 2001441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s (%d) TIOCGSERIAL", __func__, port->number); 20020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return get_serial_info(mos7720_port, 20030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman (struct serial_struct __user *)arg); 20040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 20050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman case TIOCMIWAIT: 2006441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s (%d) TIOCMIWAIT", __func__, port->number); 20070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman cprev = mos7720_port->icount; 20080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman while (1) { 20090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (signal_pending(current)) 20100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -ERESTARTSYS; 20110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman cnow = mos7720_port->icount; 20120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 20130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) 20140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -EIO; /* no change => error */ 20150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || 20160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || 20170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || 20184da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { 20190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return 0; 20200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 20210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman cprev = cnow; 20220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 20230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* NOTREACHED */ 20240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman break; 20250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 20260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 20270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -ENOIOCTLCMD; 20280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 20290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 20300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int mos7720_startup(struct usb_serial *serial) 20310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 20320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct moschip_port *mos7720_port; 20330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman struct usb_device *dev; 20340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int i; 20350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman char data; 203691f58ae61913b40da35e119017e70b3420c6f3a0Huzaifa Sidhpurwala u16 product; 2037b69578df7e98659b7d94c905971a6d1025b431adMike Dunn int ret_val; 20380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 2039441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s: Entering ..........", __func__); 20400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 20410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (!serial) { 20420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("Invalid Handler"); 20430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -ENODEV; 20440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 20450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 204691f58ae61913b40da35e119017e70b3420c6f3a0Huzaifa Sidhpurwala product = le16_to_cpu(serial->dev->descriptor.idProduct); 20470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dev = serial->dev; 20480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 2049fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn /* 2050fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * The 7715 uses the first bulk in/out endpoint pair for the parallel 2051fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * port, and the second for the serial port. Because the usbserial core 2052fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * assumes both pairs are serial ports, we must engage in a bit of 2053fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * subterfuge and swap the pointers for ports 0 and 1 in order to make 2054fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * port 0 point to the serial port. However, both moschip devices use a 2055fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * single interrupt-in endpoint for both ports (as mentioned a little 2056fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * further down), and this endpoint was assigned to port 0. So after 2057fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * the swap, we must copy the interrupt endpoint elements from port 1 2058fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * (as newly assigned) to port 0, and null out port 1 pointers. 2059fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn */ 2060fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn if (product == MOSCHIP_DEVICE_ID_7715) { 2061fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn struct usb_serial_port *tmp = serial->port[0]; 2062fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn serial->port[0] = serial->port[1]; 2063fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn serial->port[1] = tmp; 2064fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn serial->port[0]->interrupt_in_urb = tmp->interrupt_in_urb; 2065fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn serial->port[0]->interrupt_in_buffer = tmp->interrupt_in_buffer; 2066fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn serial->port[0]->interrupt_in_endpointAddress = 2067fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn tmp->interrupt_in_endpointAddress; 2068fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn serial->port[1]->interrupt_in_urb = NULL; 2069fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn serial->port[1]->interrupt_in_buffer = NULL; 2070fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn } 2071fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn 20720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 2073b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* set up serial port private structures */ 20740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman for (i = 0; i < serial->num_ports; ++i) { 20750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); 20760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman if (mos7720_port == NULL) { 2077194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&dev->dev, "%s - Out of memory\n", __func__); 20780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return -ENOMEM; 20790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 20800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 20810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* Initialize all port interrupt end point to port 0 int 20820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * endpoint. Our device has only one interrupt endpoint 2083fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn * common to all ports */ 20844da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox serial->port[i]->interrupt_in_endpointAddress = 20854da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox serial->port[0]->interrupt_in_endpointAddress; 20860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 20870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman mos7720_port->port = serial->port[i]; 20880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman usb_set_serial_port_data(serial->port[i], mos7720_port); 20890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 20900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("port number is %d", serial->port[i]->number); 20910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman dbg("serial number is %d", serial->minor); 20920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman } 20930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 20940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 20950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* setting configuration feature to one */ 20960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 20974da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5*HZ); 20980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 2099b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* start the interrupt urb */ 2100b69578df7e98659b7d94c905971a6d1025b431adMike Dunn ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL); 2101b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (ret_val) 2102b69578df7e98659b7d94c905971a6d1025b431adMike Dunn dev_err(&dev->dev, 2103b69578df7e98659b7d94c905971a6d1025b431adMike Dunn "%s - Error %d submitting control urb\n", 2104b69578df7e98659b7d94c905971a6d1025b431adMike Dunn __func__, ret_val); 2105b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 2106b69578df7e98659b7d94c905971a6d1025b431adMike Dunn#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT 2107b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (product == MOSCHIP_DEVICE_ID_7715) { 2108b69578df7e98659b7d94c905971a6d1025b431adMike Dunn ret_val = mos7715_parport_init(serial); 2109b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (ret_val < 0) 2110b69578df7e98659b7d94c905971a6d1025b431adMike Dunn return ret_val; 2111b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 2112b69578df7e98659b7d94c905971a6d1025b431adMike Dunn#endif 21134da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox /* LSR For Port 1 */ 211463b917678fe6d63e633462b5be5a309511bcf3caMike Dunn read_mos_reg(serial, 0, LSR, &data); 21154da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox dbg("LSR:%x", data); 21160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 21170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman return 0; 21180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 21190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 2120f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void mos7720_release(struct usb_serial *serial) 21210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{ 21220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman int i; 21230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 2124b69578df7e98659b7d94c905971a6d1025b431adMike Dunn#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT 2125b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* close the parallel port */ 2126b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 2127b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (le16_to_cpu(serial->dev->descriptor.idProduct) 2128b69578df7e98659b7d94c905971a6d1025b431adMike Dunn == MOSCHIP_DEVICE_ID_7715) { 2129b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct urbtracker *urbtrack; 2130b69578df7e98659b7d94c905971a6d1025b431adMike Dunn unsigned long flags; 2131b69578df7e98659b7d94c905971a6d1025b431adMike Dunn struct mos7715_parport *mos_parport = 2132b69578df7e98659b7d94c905971a6d1025b431adMike Dunn usb_get_serial_data(serial); 2133b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 2134b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* prevent NULL ptr dereference in port callbacks */ 2135b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_lock(&release_lock); 2136b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->pp->private_data = NULL; 2137b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock(&release_lock); 2138b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 2139b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* wait for synchronous usb calls to return */ 2140b69578df7e98659b7d94c905971a6d1025b431adMike Dunn if (mos_parport->msg_pending) 2141b69578df7e98659b7d94c905971a6d1025b431adMike Dunn wait_for_completion_timeout(&mos_parport->syncmsg_compl, 2142b69578df7e98659b7d94c905971a6d1025b431adMike Dunn MOS_WDR_TIMEOUT); 2143b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 2144b69578df7e98659b7d94c905971a6d1025b431adMike Dunn parport_remove_port(mos_parport->pp); 2145b69578df7e98659b7d94c905971a6d1025b431adMike Dunn usb_set_serial_data(serial, NULL); 2146b69578df7e98659b7d94c905971a6d1025b431adMike Dunn mos_parport->serial = NULL; 2147b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 2148b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* if tasklet currently scheduled, wait for it to complete */ 2149b69578df7e98659b7d94c905971a6d1025b431adMike Dunn tasklet_kill(&mos_parport->urb_tasklet); 2150b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 2151b69578df7e98659b7d94c905971a6d1025b431adMike Dunn /* unlink any urbs sent by the tasklet */ 2152b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_lock_irqsave(&mos_parport->listlock, flags); 2153b69578df7e98659b7d94c905971a6d1025b431adMike Dunn list_for_each_entry(urbtrack, 2154b69578df7e98659b7d94c905971a6d1025b431adMike Dunn &mos_parport->active_urbs, 2155b69578df7e98659b7d94c905971a6d1025b431adMike Dunn urblist_entry) 2156b69578df7e98659b7d94c905971a6d1025b431adMike Dunn usb_unlink_urb(urbtrack->urb); 2157b69578df7e98659b7d94c905971a6d1025b431adMike Dunn spin_unlock_irqrestore(&mos_parport->listlock, flags); 2158b69578df7e98659b7d94c905971a6d1025b431adMike Dunn 2159b69578df7e98659b7d94c905971a6d1025b431adMike Dunn kref_put(&mos_parport->ref_count, destroy_mos_parport); 2160b69578df7e98659b7d94c905971a6d1025b431adMike Dunn } 2161b69578df7e98659b7d94c905971a6d1025b431adMike Dunn#endif 21620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman /* free private structure allocated for serial port */ 2163f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern for (i = 0; i < serial->num_ports; ++i) 21640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman kfree(usb_get_serial_port_data(serial->port[i])); 21650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman} 21660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 2167d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzlstatic struct usb_driver usb_driver = { 2168d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl .name = "moschip7720", 2169d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl .probe = usb_serial_probe, 2170d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl .disconnect = usb_serial_disconnect, 2171d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl .id_table = moschip_port_id_table, 2172d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl}; 2173d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl 21740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic struct usb_serial_driver moschip7720_2port_driver = { 21750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .driver = { 21760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .owner = THIS_MODULE, 21770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .name = "moschip7720", 21780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman }, 21790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .description = "Moschip 2 port adapter", 21800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .id_table = moschip_port_id_table, 2181fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn .calc_num_ports = mos77xx_calc_num_ports, 21820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .open = mos7720_open, 21830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .close = mos7720_close, 21840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .throttle = mos7720_throttle, 21850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .unthrottle = mos7720_unthrottle, 2186fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn .probe = mos77xx_probe, 21870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .attach = mos7720_startup, 2188f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern .release = mos7720_release, 21890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .ioctl = mos7720_ioctl, 21900f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers .tiocmget = mos7720_tiocmget, 21910f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers .tiocmset = mos7720_tiocmset, 21920bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox .get_icount = mos7720_get_icount, 21930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .set_termios = mos7720_set_termios, 21940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .write = mos7720_write, 21950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .write_room = mos7720_write_room, 21960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .chars_in_buffer = mos7720_chars_in_buffer, 21970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .break_ctl = mos7720_break, 21980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman .read_bulk_callback = mos7720_bulk_in_callback, 2199fb088e335d78f866be2e56eac6d500112a96aa11Mike Dunn .read_int_callback = NULL /* dynamically assigned in probe() */ 22000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}; 22010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 22024d2a7aff1062048ea59214b49ca1d915586d6d6dAlan Sternstatic struct usb_serial_driver * const serial_drivers[] = { 22034d2a7aff1062048ea59214b49ca1d915586d6d6dAlan Stern &moschip7720_2port_driver, NULL 22044d2a7aff1062048ea59214b49ca1d915586d6d6dAlan Stern}; 22054d2a7aff1062048ea59214b49ca1d915586d6d6dAlan Stern 2206964e2b8425f5f37baa4f1fe6c15cdaf258d5cb51Greg Kroah-Hartmanmodule_usb_serial_driver(usb_driver, serial_drivers); 22070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 22084da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan CoxMODULE_AUTHOR(DRIVER_AUTHOR); 22094da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan CoxMODULE_DESCRIPTION(DRIVER_DESC); 22100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-HartmanMODULE_LICENSE("GPL"); 22110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman 22120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanmodule_param(debug, bool, S_IRUGO | S_IWUSR); 22130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-HartmanMODULE_PARM_DESC(debug, "Debug enabled or not"); 2214