162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Garmin GPS driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2006-2011 Hermann Kneissel herkne@gmx.de 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * The latest version of the driver can be found at 862306a36Sopenharmony_ci * http://sourceforge.net/projects/garmin-gps/ 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This driver has been derived from v2.1 of the visor driver. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/timer.h> 1762306a36Sopenharmony_ci#include <linux/tty.h> 1862306a36Sopenharmony_ci#include <linux/tty_driver.h> 1962306a36Sopenharmony_ci#include <linux/tty_flip.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/spinlock.h> 2262306a36Sopenharmony_ci#include <linux/uaccess.h> 2362306a36Sopenharmony_ci#include <linux/atomic.h> 2462306a36Sopenharmony_ci#include <linux/usb.h> 2562306a36Sopenharmony_ci#include <linux/usb/serial.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* the mode to be set when the port ist opened */ 2862306a36Sopenharmony_cistatic int initial_mode = 1; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define GARMIN_VENDOR_ID 0x091E 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * Version Information 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define VERSION_MAJOR 0 3762306a36Sopenharmony_ci#define VERSION_MINOR 36 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define _STR(s) #s 4062306a36Sopenharmony_ci#define _DRIVER_VERSION(a, b) "v" _STR(a) "." _STR(b) 4162306a36Sopenharmony_ci#define DRIVER_VERSION _DRIVER_VERSION(VERSION_MAJOR, VERSION_MINOR) 4262306a36Sopenharmony_ci#define DRIVER_AUTHOR "hermann kneissel" 4362306a36Sopenharmony_ci#define DRIVER_DESC "garmin gps driver" 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* error codes returned by the driver */ 4662306a36Sopenharmony_ci#define EINVPKT 1000 /* invalid packet structure */ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* size of the header of a packet using the usb protocol */ 5062306a36Sopenharmony_ci#define GARMIN_PKTHDR_LENGTH 12 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* max. possible size of a packet using the serial protocol */ 5362306a36Sopenharmony_ci#define MAX_SERIAL_PKT_SIZ (3 + 255 + 3) 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* max. possible size of a packet with worst case stuffing */ 5662306a36Sopenharmony_ci#define MAX_SERIAL_PKT_SIZ_STUFFED (MAX_SERIAL_PKT_SIZ + 256) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* size of a buffer able to hold a complete (no stuffing) packet 5962306a36Sopenharmony_ci * (the document protocol does not contain packets with a larger 6062306a36Sopenharmony_ci * size, but in theory a packet may be 64k+12 bytes - if in 6162306a36Sopenharmony_ci * later protocol versions larger packet sizes occur, this value 6262306a36Sopenharmony_ci * should be increased accordingly, so the input buffer is always 6362306a36Sopenharmony_ci * large enough the store a complete packet inclusive header) */ 6462306a36Sopenharmony_ci#define GPS_IN_BUFSIZ (GARMIN_PKTHDR_LENGTH+MAX_SERIAL_PKT_SIZ) 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* size of a buffer able to hold a complete (incl. stuffing) packet */ 6762306a36Sopenharmony_ci#define GPS_OUT_BUFSIZ (GARMIN_PKTHDR_LENGTH+MAX_SERIAL_PKT_SIZ_STUFFED) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* where to place the packet id of a serial packet, so we can 7062306a36Sopenharmony_ci * prepend the usb-packet header without the need to move the 7162306a36Sopenharmony_ci * packets data */ 7262306a36Sopenharmony_ci#define GSP_INITIAL_OFFSET (GARMIN_PKTHDR_LENGTH-2) 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* max. size of incoming private packets (header+1 param) */ 7562306a36Sopenharmony_ci#define PRIVPKTSIZ (GARMIN_PKTHDR_LENGTH+4) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define GARMIN_LAYERID_TRANSPORT 0 7862306a36Sopenharmony_ci#define GARMIN_LAYERID_APPL 20 7962306a36Sopenharmony_ci/* our own layer-id to use for some control mechanisms */ 8062306a36Sopenharmony_ci#define GARMIN_LAYERID_PRIVATE 0x01106E4B 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#define GARMIN_PKTID_PVT_DATA 51 8362306a36Sopenharmony_ci#define GARMIN_PKTID_L001_COMMAND_DATA 10 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#define CMND_ABORT_TRANSFER 0 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* packet ids used in private layer */ 8862306a36Sopenharmony_ci#define PRIV_PKTID_SET_DEBUG 1 8962306a36Sopenharmony_ci#define PRIV_PKTID_SET_MODE 2 9062306a36Sopenharmony_ci#define PRIV_PKTID_INFO_REQ 3 9162306a36Sopenharmony_ci#define PRIV_PKTID_INFO_RESP 4 9262306a36Sopenharmony_ci#define PRIV_PKTID_RESET_REQ 5 9362306a36Sopenharmony_ci#define PRIV_PKTID_SET_DEF_MODE 6 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#define ETX 0x03 9762306a36Sopenharmony_ci#define DLE 0x10 9862306a36Sopenharmony_ci#define ACK 0x06 9962306a36Sopenharmony_ci#define NAK 0x15 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* structure used to queue incoming packets */ 10262306a36Sopenharmony_cistruct garmin_packet { 10362306a36Sopenharmony_ci struct list_head list; 10462306a36Sopenharmony_ci int seq; 10562306a36Sopenharmony_ci /* the real size of the data array, always > 0 */ 10662306a36Sopenharmony_ci int size; 10762306a36Sopenharmony_ci __u8 data[]; 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/* structure used to keep the current state of the driver */ 11162306a36Sopenharmony_cistruct garmin_data { 11262306a36Sopenharmony_ci __u8 state; 11362306a36Sopenharmony_ci __u16 flags; 11462306a36Sopenharmony_ci __u8 mode; 11562306a36Sopenharmony_ci __u8 count; 11662306a36Sopenharmony_ci __u8 pkt_id; 11762306a36Sopenharmony_ci __u32 serial_num; 11862306a36Sopenharmony_ci struct timer_list timer; 11962306a36Sopenharmony_ci struct usb_serial_port *port; 12062306a36Sopenharmony_ci int seq_counter; 12162306a36Sopenharmony_ci int insize; 12262306a36Sopenharmony_ci int outsize; 12362306a36Sopenharmony_ci __u8 inbuffer [GPS_IN_BUFSIZ]; /* tty -> usb */ 12462306a36Sopenharmony_ci __u8 outbuffer[GPS_OUT_BUFSIZ]; /* usb -> tty */ 12562306a36Sopenharmony_ci __u8 privpkt[4*6]; 12662306a36Sopenharmony_ci spinlock_t lock; 12762306a36Sopenharmony_ci struct list_head pktlist; 12862306a36Sopenharmony_ci struct usb_anchor write_urbs; 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#define STATE_NEW 0 13362306a36Sopenharmony_ci#define STATE_INITIAL_DELAY 1 13462306a36Sopenharmony_ci#define STATE_TIMEOUT 2 13562306a36Sopenharmony_ci#define STATE_SESSION_REQ1 3 13662306a36Sopenharmony_ci#define STATE_SESSION_REQ2 4 13762306a36Sopenharmony_ci#define STATE_ACTIVE 5 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci#define STATE_RESET 8 14062306a36Sopenharmony_ci#define STATE_DISCONNECTED 9 14162306a36Sopenharmony_ci#define STATE_WAIT_TTY_ACK 10 14262306a36Sopenharmony_ci#define STATE_GSP_WAIT_DATA 11 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci#define MODE_NATIVE 0 14562306a36Sopenharmony_ci#define MODE_GARMIN_SERIAL 1 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/* Flags used in garmin_data.flags: */ 14862306a36Sopenharmony_ci#define FLAGS_SESSION_REPLY_MASK 0x00C0 14962306a36Sopenharmony_ci#define FLAGS_SESSION_REPLY1_SEEN 0x0080 15062306a36Sopenharmony_ci#define FLAGS_SESSION_REPLY2_SEEN 0x0040 15162306a36Sopenharmony_ci#define FLAGS_BULK_IN_ACTIVE 0x0020 15262306a36Sopenharmony_ci#define FLAGS_BULK_IN_RESTART 0x0010 15362306a36Sopenharmony_ci#define FLAGS_THROTTLED 0x0008 15462306a36Sopenharmony_ci#define APP_REQ_SEEN 0x0004 15562306a36Sopenharmony_ci#define APP_RESP_SEEN 0x0002 15662306a36Sopenharmony_ci#define CLEAR_HALT_REQUIRED 0x0001 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#define FLAGS_QUEUING 0x0100 15962306a36Sopenharmony_ci#define FLAGS_DROP_DATA 0x0800 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci#define FLAGS_GSP_SKIP 0x1000 16262306a36Sopenharmony_ci#define FLAGS_GSP_DLESEEN 0x2000 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* function prototypes */ 17062306a36Sopenharmony_cistatic int gsp_next_packet(struct garmin_data *garmin_data_p); 17162306a36Sopenharmony_cistatic int garmin_write_bulk(struct usb_serial_port *port, 17262306a36Sopenharmony_ci const unsigned char *buf, int count, 17362306a36Sopenharmony_ci int dismiss_ack); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* some special packets to be send or received */ 17662306a36Sopenharmony_cistatic unsigned char const GARMIN_START_SESSION_REQ[] 17762306a36Sopenharmony_ci = { 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0 }; 17862306a36Sopenharmony_cistatic unsigned char const GARMIN_START_SESSION_REPLY[] 17962306a36Sopenharmony_ci = { 0, 0, 0, 0, 6, 0, 0, 0, 4, 0, 0, 0 }; 18062306a36Sopenharmony_cistatic unsigned char const GARMIN_BULK_IN_AVAIL_REPLY[] 18162306a36Sopenharmony_ci = { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 }; 18262306a36Sopenharmony_cistatic unsigned char const GARMIN_STOP_TRANSFER_REQ[] 18362306a36Sopenharmony_ci = { 20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 0, 0 }; 18462306a36Sopenharmony_cistatic unsigned char const GARMIN_STOP_TRANSFER_REQ_V2[] 18562306a36Sopenharmony_ci = { 20, 0, 0, 0, 10, 0, 0, 0, 1, 0, 0, 0, 0 }; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/* packets currently unused, left as documentation */ 18862306a36Sopenharmony_ci#if 0 18962306a36Sopenharmony_cistatic unsigned char const GARMIN_APP_LAYER_REPLY[] 19062306a36Sopenharmony_ci = { 0x14, 0, 0, 0 }; 19162306a36Sopenharmony_cistatic unsigned char const GARMIN_START_PVT_REQ[] 19262306a36Sopenharmony_ci = { 20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 49, 0 }; 19362306a36Sopenharmony_cistatic unsigned char const GARMIN_STOP_PVT_REQ[] 19462306a36Sopenharmony_ci = { 20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 50, 0 }; 19562306a36Sopenharmony_cistatic unsigned char const PRIVATE_REQ[] 19662306a36Sopenharmony_ci = { 0x4B, 0x6E, 0x10, 0x01, 0xFF, 0, 0, 0, 0xFF, 0, 0, 0 }; 19762306a36Sopenharmony_ci#endif 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic const struct usb_device_id id_table[] = { 20162306a36Sopenharmony_ci /* the same device id seems to be used by all 20262306a36Sopenharmony_ci usb enabled GPS devices */ 20362306a36Sopenharmony_ci { USB_DEVICE(GARMIN_VENDOR_ID, 3) }, 20462306a36Sopenharmony_ci { } /* Terminating entry */ 20562306a36Sopenharmony_ci}; 20662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic inline int getLayerId(const __u8 *usbPacket) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci return __le32_to_cpup((__le32 *)(usbPacket)); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic inline int getPacketId(const __u8 *usbPacket) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci return __le32_to_cpup((__le32 *)(usbPacket+4)); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic inline int getDataLength(const __u8 *usbPacket) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci return __le32_to_cpup((__le32 *)(usbPacket+8)); 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/* 22662306a36Sopenharmony_ci * check if the usb-packet in buf contains an abort-transfer command. 22762306a36Sopenharmony_ci * (if yes, all queued data will be dropped) 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_cistatic inline int isAbortTrfCmnd(const unsigned char *buf) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci if (memcmp(buf, GARMIN_STOP_TRANSFER_REQ, 23262306a36Sopenharmony_ci sizeof(GARMIN_STOP_TRANSFER_REQ)) == 0 || 23362306a36Sopenharmony_ci memcmp(buf, GARMIN_STOP_TRANSFER_REQ_V2, 23462306a36Sopenharmony_ci sizeof(GARMIN_STOP_TRANSFER_REQ_V2)) == 0) 23562306a36Sopenharmony_ci return 1; 23662306a36Sopenharmony_ci else 23762306a36Sopenharmony_ci return 0; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic void send_to_tty(struct usb_serial_port *port, 24362306a36Sopenharmony_ci char *data, unsigned int actual_length) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci if (actual_length) { 24662306a36Sopenharmony_ci usb_serial_debug_data(&port->dev, __func__, actual_length, data); 24762306a36Sopenharmony_ci tty_insert_flip_string(&port->port, data, actual_length); 24862306a36Sopenharmony_ci tty_flip_buffer_push(&port->port); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci/****************************************************************************** 25462306a36Sopenharmony_ci * packet queue handling 25562306a36Sopenharmony_ci ******************************************************************************/ 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/* 25862306a36Sopenharmony_ci * queue a received (usb-)packet for later processing 25962306a36Sopenharmony_ci */ 26062306a36Sopenharmony_cistatic int pkt_add(struct garmin_data *garmin_data_p, 26162306a36Sopenharmony_ci unsigned char *data, unsigned int data_length) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci int state = 0; 26462306a36Sopenharmony_ci int result = 0; 26562306a36Sopenharmony_ci unsigned long flags; 26662306a36Sopenharmony_ci struct garmin_packet *pkt; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* process only packets containing data ... */ 26962306a36Sopenharmony_ci if (data_length) { 27062306a36Sopenharmony_ci pkt = kmalloc(sizeof(struct garmin_packet)+data_length, 27162306a36Sopenharmony_ci GFP_ATOMIC); 27262306a36Sopenharmony_ci if (!pkt) 27362306a36Sopenharmony_ci return 0; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci pkt->size = data_length; 27662306a36Sopenharmony_ci memcpy(pkt->data, data, data_length); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 27962306a36Sopenharmony_ci garmin_data_p->flags |= FLAGS_QUEUING; 28062306a36Sopenharmony_ci result = list_empty(&garmin_data_p->pktlist); 28162306a36Sopenharmony_ci pkt->seq = garmin_data_p->seq_counter++; 28262306a36Sopenharmony_ci list_add_tail(&pkt->list, &garmin_data_p->pktlist); 28362306a36Sopenharmony_ci state = garmin_data_p->state; 28462306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci dev_dbg(&garmin_data_p->port->dev, 28762306a36Sopenharmony_ci "%s - added: pkt: %d - %d bytes\n", __func__, 28862306a36Sopenharmony_ci pkt->seq, data_length); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* in serial mode, if someone is waiting for data from 29162306a36Sopenharmony_ci the device, convert and send the next packet to tty. */ 29262306a36Sopenharmony_ci if (result && (state == STATE_GSP_WAIT_DATA)) 29362306a36Sopenharmony_ci gsp_next_packet(garmin_data_p); 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci return result; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/* get the next pending packet */ 30062306a36Sopenharmony_cistatic struct garmin_packet *pkt_pop(struct garmin_data *garmin_data_p) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci unsigned long flags; 30362306a36Sopenharmony_ci struct garmin_packet *result = NULL; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 30662306a36Sopenharmony_ci if (!list_empty(&garmin_data_p->pktlist)) { 30762306a36Sopenharmony_ci result = (struct garmin_packet *)garmin_data_p->pktlist.next; 30862306a36Sopenharmony_ci list_del(&result->list); 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 31162306a36Sopenharmony_ci return result; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci/* free up all queued data */ 31662306a36Sopenharmony_cistatic void pkt_clear(struct garmin_data *garmin_data_p) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci unsigned long flags; 31962306a36Sopenharmony_ci struct garmin_packet *result = NULL; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 32262306a36Sopenharmony_ci while (!list_empty(&garmin_data_p->pktlist)) { 32362306a36Sopenharmony_ci result = (struct garmin_packet *)garmin_data_p->pktlist.next; 32462306a36Sopenharmony_ci list_del(&result->list); 32562306a36Sopenharmony_ci kfree(result); 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci/****************************************************************************** 33262306a36Sopenharmony_ci * garmin serial protocol handling handling 33362306a36Sopenharmony_ci ******************************************************************************/ 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci/* send an ack packet back to the tty */ 33662306a36Sopenharmony_cistatic int gsp_send_ack(struct garmin_data *garmin_data_p, __u8 pkt_id) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci __u8 pkt[10]; 33962306a36Sopenharmony_ci __u8 cksum = 0; 34062306a36Sopenharmony_ci __u8 *ptr = pkt; 34162306a36Sopenharmony_ci unsigned l = 0; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci dev_dbg(&garmin_data_p->port->dev, "%s - pkt-id: 0x%X.\n", __func__, 34462306a36Sopenharmony_ci pkt_id); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci *ptr++ = DLE; 34762306a36Sopenharmony_ci *ptr++ = ACK; 34862306a36Sopenharmony_ci cksum += ACK; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci *ptr++ = 2; 35162306a36Sopenharmony_ci cksum += 2; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci *ptr++ = pkt_id; 35462306a36Sopenharmony_ci cksum += pkt_id; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (pkt_id == DLE) 35762306a36Sopenharmony_ci *ptr++ = DLE; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci *ptr++ = 0; 36062306a36Sopenharmony_ci *ptr++ = (-cksum) & 0xFF; 36162306a36Sopenharmony_ci *ptr++ = DLE; 36262306a36Sopenharmony_ci *ptr++ = ETX; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci l = ptr-pkt; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci send_to_tty(garmin_data_p->port, pkt, l); 36762306a36Sopenharmony_ci return 0; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci/* 37362306a36Sopenharmony_ci * called for a complete packet received from tty layer 37462306a36Sopenharmony_ci * 37562306a36Sopenharmony_ci * the complete packet (pktid ... cksum) is in garmin_data_p->inbuf starting 37662306a36Sopenharmony_ci * at GSP_INITIAL_OFFSET. 37762306a36Sopenharmony_ci * 37862306a36Sopenharmony_ci * count - number of bytes in the input buffer including space reserved for 37962306a36Sopenharmony_ci * the usb header: GSP_INITIAL_OFFSET + number of bytes in packet 38062306a36Sopenharmony_ci * (including pkt-id, data-length a. cksum) 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_cistatic int gsp_rec_packet(struct garmin_data *garmin_data_p, int count) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct device *dev = &garmin_data_p->port->dev; 38562306a36Sopenharmony_ci unsigned long flags; 38662306a36Sopenharmony_ci const __u8 *recpkt = garmin_data_p->inbuffer+GSP_INITIAL_OFFSET; 38762306a36Sopenharmony_ci __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer; 38862306a36Sopenharmony_ci int cksum = 0; 38962306a36Sopenharmony_ci int n = 0; 39062306a36Sopenharmony_ci int pktid = recpkt[0]; 39162306a36Sopenharmony_ci int size = recpkt[1]; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci usb_serial_debug_data(&garmin_data_p->port->dev, __func__, 39462306a36Sopenharmony_ci count-GSP_INITIAL_OFFSET, recpkt); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (size != (count-GSP_INITIAL_OFFSET-3)) { 39762306a36Sopenharmony_ci dev_dbg(dev, "%s - invalid size, expected %d bytes, got %d\n", 39862306a36Sopenharmony_ci __func__, size, (count-GSP_INITIAL_OFFSET-3)); 39962306a36Sopenharmony_ci return -EINVPKT; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci cksum += *recpkt++; 40362306a36Sopenharmony_ci cksum += *recpkt++; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* sanity check, remove after test ... */ 40662306a36Sopenharmony_ci if ((__u8 *)&(usbdata[3]) != recpkt) { 40762306a36Sopenharmony_ci dev_dbg(dev, "%s - ptr mismatch %p - %p\n", __func__, 40862306a36Sopenharmony_ci &(usbdata[4]), recpkt); 40962306a36Sopenharmony_ci return -EINVPKT; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci while (n < size) { 41362306a36Sopenharmony_ci cksum += *recpkt++; 41462306a36Sopenharmony_ci n++; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (((cksum + *recpkt) & 0xff) != 0) { 41862306a36Sopenharmony_ci dev_dbg(dev, "%s - invalid checksum, expected %02x, got %02x\n", 41962306a36Sopenharmony_ci __func__, -cksum & 0xff, *recpkt); 42062306a36Sopenharmony_ci return -EINVPKT; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci usbdata[0] = __cpu_to_le32(GARMIN_LAYERID_APPL); 42462306a36Sopenharmony_ci usbdata[1] = __cpu_to_le32(pktid); 42562306a36Sopenharmony_ci usbdata[2] = __cpu_to_le32(size); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci garmin_write_bulk(garmin_data_p->port, garmin_data_p->inbuffer, 42862306a36Sopenharmony_ci GARMIN_PKTHDR_LENGTH+size, 0); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* if this was an abort-transfer command, flush all 43162306a36Sopenharmony_ci queued data. */ 43262306a36Sopenharmony_ci if (isAbortTrfCmnd(garmin_data_p->inbuffer)) { 43362306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 43462306a36Sopenharmony_ci garmin_data_p->flags |= FLAGS_DROP_DATA; 43562306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 43662306a36Sopenharmony_ci pkt_clear(garmin_data_p); 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci return count; 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci/* 44562306a36Sopenharmony_ci * Called for data received from tty 44662306a36Sopenharmony_ci * 44762306a36Sopenharmony_ci * buf contains the data read, it may span more than one packet or even 44862306a36Sopenharmony_ci * incomplete packets 44962306a36Sopenharmony_ci * 45062306a36Sopenharmony_ci * input record should be a serial-record, but it may not be complete. 45162306a36Sopenharmony_ci * Copy it into our local buffer, until an etx is seen (or an error 45262306a36Sopenharmony_ci * occurs). 45362306a36Sopenharmony_ci * Once the record is complete, convert into a usb packet and send it 45462306a36Sopenharmony_ci * to the bulk pipe, send an ack back to the tty. 45562306a36Sopenharmony_ci * 45662306a36Sopenharmony_ci * If the input is an ack, just send the last queued packet to the 45762306a36Sopenharmony_ci * tty layer. 45862306a36Sopenharmony_ci * 45962306a36Sopenharmony_ci * if the input is an abort command, drop all queued data. 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic int gsp_receive(struct garmin_data *garmin_data_p, 46362306a36Sopenharmony_ci const unsigned char *buf, int count) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct device *dev = &garmin_data_p->port->dev; 46662306a36Sopenharmony_ci unsigned long flags; 46762306a36Sopenharmony_ci int offs = 0; 46862306a36Sopenharmony_ci int ack_or_nak_seen = 0; 46962306a36Sopenharmony_ci __u8 *dest; 47062306a36Sopenharmony_ci int size; 47162306a36Sopenharmony_ci /* dleSeen: set if last byte read was a DLE */ 47262306a36Sopenharmony_ci int dleSeen; 47362306a36Sopenharmony_ci /* skip: if set, skip incoming data until possible start of 47462306a36Sopenharmony_ci * new packet 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_ci int skip; 47762306a36Sopenharmony_ci __u8 data; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 48062306a36Sopenharmony_ci dest = garmin_data_p->inbuffer; 48162306a36Sopenharmony_ci size = garmin_data_p->insize; 48262306a36Sopenharmony_ci dleSeen = garmin_data_p->flags & FLAGS_GSP_DLESEEN; 48362306a36Sopenharmony_ci skip = garmin_data_p->flags & FLAGS_GSP_SKIP; 48462306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* dev_dbg(dev, "%s - dle=%d skip=%d size=%d count=%d\n", 48762306a36Sopenharmony_ci __func__, dleSeen, skip, size, count); */ 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (size == 0) 49062306a36Sopenharmony_ci size = GSP_INITIAL_OFFSET; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci while (offs < count) { 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci data = *(buf+offs); 49562306a36Sopenharmony_ci offs++; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (data == DLE) { 49862306a36Sopenharmony_ci if (skip) { /* start of a new pkt */ 49962306a36Sopenharmony_ci skip = 0; 50062306a36Sopenharmony_ci size = GSP_INITIAL_OFFSET; 50162306a36Sopenharmony_ci dleSeen = 1; 50262306a36Sopenharmony_ci } else if (dleSeen) { 50362306a36Sopenharmony_ci dest[size++] = data; 50462306a36Sopenharmony_ci dleSeen = 0; 50562306a36Sopenharmony_ci } else { 50662306a36Sopenharmony_ci dleSeen = 1; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci } else if (data == ETX) { 50962306a36Sopenharmony_ci if (dleSeen) { 51062306a36Sopenharmony_ci /* packet complete */ 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci data = dest[GSP_INITIAL_OFFSET]; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (data == ACK) { 51562306a36Sopenharmony_ci ack_or_nak_seen = ACK; 51662306a36Sopenharmony_ci dev_dbg(dev, "ACK packet complete.\n"); 51762306a36Sopenharmony_ci } else if (data == NAK) { 51862306a36Sopenharmony_ci ack_or_nak_seen = NAK; 51962306a36Sopenharmony_ci dev_dbg(dev, "NAK packet complete.\n"); 52062306a36Sopenharmony_ci } else { 52162306a36Sopenharmony_ci dev_dbg(dev, "packet complete - id=0x%X.\n", 52262306a36Sopenharmony_ci data); 52362306a36Sopenharmony_ci gsp_rec_packet(garmin_data_p, size); 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci skip = 1; 52762306a36Sopenharmony_ci size = GSP_INITIAL_OFFSET; 52862306a36Sopenharmony_ci dleSeen = 0; 52962306a36Sopenharmony_ci } else { 53062306a36Sopenharmony_ci dest[size++] = data; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci } else if (!skip) { 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (dleSeen) { 53562306a36Sopenharmony_ci size = GSP_INITIAL_OFFSET; 53662306a36Sopenharmony_ci dleSeen = 0; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci dest[size++] = data; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (size >= GPS_IN_BUFSIZ) { 54362306a36Sopenharmony_ci dev_dbg(dev, "%s - packet too large.\n", __func__); 54462306a36Sopenharmony_ci skip = 1; 54562306a36Sopenharmony_ci size = GSP_INITIAL_OFFSET; 54662306a36Sopenharmony_ci dleSeen = 0; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci garmin_data_p->insize = size; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* copy flags back to structure */ 55562306a36Sopenharmony_ci if (skip) 55662306a36Sopenharmony_ci garmin_data_p->flags |= FLAGS_GSP_SKIP; 55762306a36Sopenharmony_ci else 55862306a36Sopenharmony_ci garmin_data_p->flags &= ~FLAGS_GSP_SKIP; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (dleSeen) 56162306a36Sopenharmony_ci garmin_data_p->flags |= FLAGS_GSP_DLESEEN; 56262306a36Sopenharmony_ci else 56362306a36Sopenharmony_ci garmin_data_p->flags &= ~FLAGS_GSP_DLESEEN; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (ack_or_nak_seen) { 56862306a36Sopenharmony_ci if (gsp_next_packet(garmin_data_p) > 0) 56962306a36Sopenharmony_ci garmin_data_p->state = STATE_ACTIVE; 57062306a36Sopenharmony_ci else 57162306a36Sopenharmony_ci garmin_data_p->state = STATE_GSP_WAIT_DATA; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci return count; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci/* 57962306a36Sopenharmony_ci * Sends a usb packet to the tty 58062306a36Sopenharmony_ci * 58162306a36Sopenharmony_ci * Assumes, that all packages and at an usb-packet boundary. 58262306a36Sopenharmony_ci * 58362306a36Sopenharmony_ci * return <0 on error, 0 if packet is incomplete or > 0 if packet was sent 58462306a36Sopenharmony_ci */ 58562306a36Sopenharmony_cistatic int gsp_send(struct garmin_data *garmin_data_p, 58662306a36Sopenharmony_ci const unsigned char *buf, int count) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct device *dev = &garmin_data_p->port->dev; 58962306a36Sopenharmony_ci const unsigned char *src; 59062306a36Sopenharmony_ci unsigned char *dst; 59162306a36Sopenharmony_ci int pktid = 0; 59262306a36Sopenharmony_ci int datalen = 0; 59362306a36Sopenharmony_ci int cksum = 0; 59462306a36Sopenharmony_ci int i = 0; 59562306a36Sopenharmony_ci int k; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci dev_dbg(dev, "%s - state %d - %d bytes.\n", __func__, 59862306a36Sopenharmony_ci garmin_data_p->state, count); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci k = garmin_data_p->outsize; 60162306a36Sopenharmony_ci if ((k+count) > GPS_OUT_BUFSIZ) { 60262306a36Sopenharmony_ci dev_dbg(dev, "packet too large\n"); 60362306a36Sopenharmony_ci garmin_data_p->outsize = 0; 60462306a36Sopenharmony_ci return -4; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci memcpy(garmin_data_p->outbuffer+k, buf, count); 60862306a36Sopenharmony_ci k += count; 60962306a36Sopenharmony_ci garmin_data_p->outsize = k; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (k >= GARMIN_PKTHDR_LENGTH) { 61262306a36Sopenharmony_ci pktid = getPacketId(garmin_data_p->outbuffer); 61362306a36Sopenharmony_ci datalen = getDataLength(garmin_data_p->outbuffer); 61462306a36Sopenharmony_ci i = GARMIN_PKTHDR_LENGTH + datalen; 61562306a36Sopenharmony_ci if (k < i) 61662306a36Sopenharmony_ci return 0; 61762306a36Sopenharmony_ci } else { 61862306a36Sopenharmony_ci return 0; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci dev_dbg(dev, "%s - %d bytes in buffer, %d bytes in pkt.\n", __func__, k, i); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* garmin_data_p->outbuffer now contains a complete packet */ 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci usb_serial_debug_data(&garmin_data_p->port->dev, __func__, k, 62662306a36Sopenharmony_ci garmin_data_p->outbuffer); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci garmin_data_p->outsize = 0; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (getLayerId(garmin_data_p->outbuffer) != GARMIN_LAYERID_APPL) { 63162306a36Sopenharmony_ci dev_dbg(dev, "not an application packet (%d)\n", 63262306a36Sopenharmony_ci getLayerId(garmin_data_p->outbuffer)); 63362306a36Sopenharmony_ci return -1; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (pktid > 255) { 63762306a36Sopenharmony_ci dev_dbg(dev, "packet-id %d too large\n", pktid); 63862306a36Sopenharmony_ci return -2; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (datalen > 255) { 64262306a36Sopenharmony_ci dev_dbg(dev, "packet-size %d too large\n", datalen); 64362306a36Sopenharmony_ci return -3; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* the serial protocol should be able to handle this packet */ 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci k = 0; 64962306a36Sopenharmony_ci src = garmin_data_p->outbuffer+GARMIN_PKTHDR_LENGTH; 65062306a36Sopenharmony_ci for (i = 0; i < datalen; i++) { 65162306a36Sopenharmony_ci if (*src++ == DLE) 65262306a36Sopenharmony_ci k++; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci src = garmin_data_p->outbuffer+GARMIN_PKTHDR_LENGTH; 65662306a36Sopenharmony_ci if (k > (GARMIN_PKTHDR_LENGTH-2)) { 65762306a36Sopenharmony_ci /* can't add stuffing DLEs in place, move data to end 65862306a36Sopenharmony_ci of buffer ... */ 65962306a36Sopenharmony_ci dst = garmin_data_p->outbuffer+GPS_OUT_BUFSIZ-datalen; 66062306a36Sopenharmony_ci memcpy(dst, src, datalen); 66162306a36Sopenharmony_ci src = dst; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci dst = garmin_data_p->outbuffer; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci *dst++ = DLE; 66762306a36Sopenharmony_ci *dst++ = pktid; 66862306a36Sopenharmony_ci cksum += pktid; 66962306a36Sopenharmony_ci *dst++ = datalen; 67062306a36Sopenharmony_ci cksum += datalen; 67162306a36Sopenharmony_ci if (datalen == DLE) 67262306a36Sopenharmony_ci *dst++ = DLE; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci for (i = 0; i < datalen; i++) { 67562306a36Sopenharmony_ci __u8 c = *src++; 67662306a36Sopenharmony_ci *dst++ = c; 67762306a36Sopenharmony_ci cksum += c; 67862306a36Sopenharmony_ci if (c == DLE) 67962306a36Sopenharmony_ci *dst++ = DLE; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci cksum = -cksum & 0xFF; 68362306a36Sopenharmony_ci *dst++ = cksum; 68462306a36Sopenharmony_ci if (cksum == DLE) 68562306a36Sopenharmony_ci *dst++ = DLE; 68662306a36Sopenharmony_ci *dst++ = DLE; 68762306a36Sopenharmony_ci *dst++ = ETX; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci i = dst-garmin_data_p->outbuffer; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci send_to_tty(garmin_data_p->port, garmin_data_p->outbuffer, i); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci garmin_data_p->pkt_id = pktid; 69462306a36Sopenharmony_ci garmin_data_p->state = STATE_WAIT_TTY_ACK; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci return i; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci/* 70162306a36Sopenharmony_ci * Process the next pending data packet - if there is one 70262306a36Sopenharmony_ci */ 70362306a36Sopenharmony_cistatic int gsp_next_packet(struct garmin_data *garmin_data_p) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci int result = 0; 70662306a36Sopenharmony_ci struct garmin_packet *pkt = NULL; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci while ((pkt = pkt_pop(garmin_data_p)) != NULL) { 70962306a36Sopenharmony_ci dev_dbg(&garmin_data_p->port->dev, "%s - next pkt: %d\n", __func__, pkt->seq); 71062306a36Sopenharmony_ci result = gsp_send(garmin_data_p, pkt->data, pkt->size); 71162306a36Sopenharmony_ci if (result > 0) { 71262306a36Sopenharmony_ci kfree(pkt); 71362306a36Sopenharmony_ci return result; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci kfree(pkt); 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci return result; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci/****************************************************************************** 72362306a36Sopenharmony_ci * garmin native mode 72462306a36Sopenharmony_ci ******************************************************************************/ 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci/* 72862306a36Sopenharmony_ci * Called for data received from tty 72962306a36Sopenharmony_ci * 73062306a36Sopenharmony_ci * The input data is expected to be in garmin usb-packet format. 73162306a36Sopenharmony_ci * 73262306a36Sopenharmony_ci * buf contains the data read, it may span more than one packet 73362306a36Sopenharmony_ci * or even incomplete packets 73462306a36Sopenharmony_ci */ 73562306a36Sopenharmony_cistatic int nat_receive(struct garmin_data *garmin_data_p, 73662306a36Sopenharmony_ci const unsigned char *buf, int count) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci unsigned long flags; 73962306a36Sopenharmony_ci __u8 *dest; 74062306a36Sopenharmony_ci int offs = 0; 74162306a36Sopenharmony_ci int result = count; 74262306a36Sopenharmony_ci int len; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci while (offs < count) { 74562306a36Sopenharmony_ci /* if buffer contains header, copy rest of data */ 74662306a36Sopenharmony_ci if (garmin_data_p->insize >= GARMIN_PKTHDR_LENGTH) 74762306a36Sopenharmony_ci len = GARMIN_PKTHDR_LENGTH 74862306a36Sopenharmony_ci +getDataLength(garmin_data_p->inbuffer); 74962306a36Sopenharmony_ci else 75062306a36Sopenharmony_ci len = GARMIN_PKTHDR_LENGTH; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (len >= GPS_IN_BUFSIZ) { 75362306a36Sopenharmony_ci /* seems to be an invalid packet, ignore rest 75462306a36Sopenharmony_ci of input */ 75562306a36Sopenharmony_ci dev_dbg(&garmin_data_p->port->dev, 75662306a36Sopenharmony_ci "%s - packet size too large: %d\n", 75762306a36Sopenharmony_ci __func__, len); 75862306a36Sopenharmony_ci garmin_data_p->insize = 0; 75962306a36Sopenharmony_ci count = 0; 76062306a36Sopenharmony_ci result = -EINVPKT; 76162306a36Sopenharmony_ci } else { 76262306a36Sopenharmony_ci len -= garmin_data_p->insize; 76362306a36Sopenharmony_ci if (len > (count-offs)) 76462306a36Sopenharmony_ci len = (count-offs); 76562306a36Sopenharmony_ci if (len > 0) { 76662306a36Sopenharmony_ci dest = garmin_data_p->inbuffer 76762306a36Sopenharmony_ci + garmin_data_p->insize; 76862306a36Sopenharmony_ci memcpy(dest, buf+offs, len); 76962306a36Sopenharmony_ci garmin_data_p->insize += len; 77062306a36Sopenharmony_ci offs += len; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci /* do we have a complete packet ? */ 77562306a36Sopenharmony_ci if (garmin_data_p->insize >= GARMIN_PKTHDR_LENGTH) { 77662306a36Sopenharmony_ci len = GARMIN_PKTHDR_LENGTH+ 77762306a36Sopenharmony_ci getDataLength(garmin_data_p->inbuffer); 77862306a36Sopenharmony_ci if (garmin_data_p->insize >= len) { 77962306a36Sopenharmony_ci garmin_write_bulk(garmin_data_p->port, 78062306a36Sopenharmony_ci garmin_data_p->inbuffer, 78162306a36Sopenharmony_ci len, 0); 78262306a36Sopenharmony_ci garmin_data_p->insize = 0; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci /* if this was an abort-transfer command, 78562306a36Sopenharmony_ci flush all queued data. */ 78662306a36Sopenharmony_ci if (isAbortTrfCmnd(garmin_data_p->inbuffer)) { 78762306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, 78862306a36Sopenharmony_ci flags); 78962306a36Sopenharmony_ci garmin_data_p->flags |= FLAGS_DROP_DATA; 79062306a36Sopenharmony_ci spin_unlock_irqrestore( 79162306a36Sopenharmony_ci &garmin_data_p->lock, flags); 79262306a36Sopenharmony_ci pkt_clear(garmin_data_p); 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci return result; 79862306a36Sopenharmony_ci} 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci/****************************************************************************** 80262306a36Sopenharmony_ci * private packets 80362306a36Sopenharmony_ci ******************************************************************************/ 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic void priv_status_resp(struct usb_serial_port *port) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 80862306a36Sopenharmony_ci __le32 *pkt = (__le32 *)garmin_data_p->privpkt; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci pkt[0] = __cpu_to_le32(GARMIN_LAYERID_PRIVATE); 81162306a36Sopenharmony_ci pkt[1] = __cpu_to_le32(PRIV_PKTID_INFO_RESP); 81262306a36Sopenharmony_ci pkt[2] = __cpu_to_le32(12); 81362306a36Sopenharmony_ci pkt[3] = __cpu_to_le32(VERSION_MAJOR << 16 | VERSION_MINOR); 81462306a36Sopenharmony_ci pkt[4] = __cpu_to_le32(garmin_data_p->mode); 81562306a36Sopenharmony_ci pkt[5] = __cpu_to_le32(garmin_data_p->serial_num); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci send_to_tty(port, (__u8 *)pkt, 6 * 4); 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci/****************************************************************************** 82262306a36Sopenharmony_ci * Garmin specific driver functions 82362306a36Sopenharmony_ci ******************************************************************************/ 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic int process_resetdev_request(struct usb_serial_port *port) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci unsigned long flags; 82862306a36Sopenharmony_ci int status; 82962306a36Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 83262306a36Sopenharmony_ci garmin_data_p->flags &= ~(CLEAR_HALT_REQUIRED); 83362306a36Sopenharmony_ci garmin_data_p->state = STATE_RESET; 83462306a36Sopenharmony_ci garmin_data_p->serial_num = 0; 83562306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 83862306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - usb_reset_device\n", __func__); 83962306a36Sopenharmony_ci status = usb_reset_device(port->serial->dev); 84062306a36Sopenharmony_ci if (status) 84162306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - usb_reset_device failed: %d\n", 84262306a36Sopenharmony_ci __func__, status); 84362306a36Sopenharmony_ci return status; 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci/* 84962306a36Sopenharmony_ci * clear all cached data 85062306a36Sopenharmony_ci */ 85162306a36Sopenharmony_cistatic int garmin_clear(struct garmin_data *garmin_data_p) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci unsigned long flags; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci /* flush all queued data */ 85662306a36Sopenharmony_ci pkt_clear(garmin_data_p); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 85962306a36Sopenharmony_ci garmin_data_p->insize = 0; 86062306a36Sopenharmony_ci garmin_data_p->outsize = 0; 86162306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci return 0; 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic int garmin_init_session(struct usb_serial_port *port) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 87062306a36Sopenharmony_ci int status; 87162306a36Sopenharmony_ci int i; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 87662306a36Sopenharmony_ci if (status) { 87762306a36Sopenharmony_ci dev_err(&port->dev, "failed to submit interrupt urb: %d\n", 87862306a36Sopenharmony_ci status); 87962306a36Sopenharmony_ci return status; 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* 88362306a36Sopenharmony_ci * using the initialization method from gpsbabel. See comments in 88462306a36Sopenharmony_ci * gpsbabel/jeeps/gpslibusb.c gusb_reset_toggles() 88562306a36Sopenharmony_ci */ 88662306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - starting session ...\n", __func__); 88762306a36Sopenharmony_ci garmin_data_p->state = STATE_ACTIVE; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci for (i = 0; i < 3; i++) { 89062306a36Sopenharmony_ci status = garmin_write_bulk(port, GARMIN_START_SESSION_REQ, 89162306a36Sopenharmony_ci sizeof(GARMIN_START_SESSION_REQ), 0); 89262306a36Sopenharmony_ci if (status < 0) 89362306a36Sopenharmony_ci goto err_kill_urbs; 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci return 0; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cierr_kill_urbs: 89962306a36Sopenharmony_ci usb_kill_anchored_urbs(&garmin_data_p->write_urbs); 90062306a36Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci return status; 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic int garmin_open(struct tty_struct *tty, struct usb_serial_port *port) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci unsigned long flags; 91062306a36Sopenharmony_ci int status = 0; 91162306a36Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 91462306a36Sopenharmony_ci garmin_data_p->mode = initial_mode; 91562306a36Sopenharmony_ci garmin_data_p->count = 0; 91662306a36Sopenharmony_ci garmin_data_p->flags &= FLAGS_SESSION_REPLY1_SEEN; 91762306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci /* shutdown any bulk reads that might be going on */ 92062306a36Sopenharmony_ci usb_kill_urb(port->read_urb); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (garmin_data_p->state == STATE_RESET) 92362306a36Sopenharmony_ci status = garmin_init_session(port); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci garmin_data_p->state = STATE_ACTIVE; 92662306a36Sopenharmony_ci return status; 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_cistatic void garmin_close(struct usb_serial_port *port) 93162306a36Sopenharmony_ci{ 93262306a36Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - mode=%d state=%d flags=0x%X\n", 93562306a36Sopenharmony_ci __func__, garmin_data_p->mode, garmin_data_p->state, 93662306a36Sopenharmony_ci garmin_data_p->flags); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci garmin_clear(garmin_data_p); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci /* shutdown our urbs */ 94162306a36Sopenharmony_ci usb_kill_urb(port->read_urb); 94262306a36Sopenharmony_ci usb_kill_anchored_urbs(&garmin_data_p->write_urbs); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci /* keep reset state so we know that we must start a new session */ 94562306a36Sopenharmony_ci if (garmin_data_p->state != STATE_RESET) 94662306a36Sopenharmony_ci garmin_data_p->state = STATE_DISCONNECTED; 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistatic void garmin_write_bulk_callback(struct urb *urb) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci if (port) { 95562306a36Sopenharmony_ci struct garmin_data *garmin_data_p = 95662306a36Sopenharmony_ci usb_get_serial_port_data(port); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if (getLayerId(urb->transfer_buffer) == GARMIN_LAYERID_APPL) { 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { 96162306a36Sopenharmony_ci gsp_send_ack(garmin_data_p, 96262306a36Sopenharmony_ci ((__u8 *)urb->transfer_buffer)[4]); 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci usb_serial_port_softint(port); 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* Ignore errors that resulted from garmin_write_bulk with 96962306a36Sopenharmony_ci dismiss_ack = 1 */ 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci /* free up the transfer buffer, as usb_free_urb() does not do this */ 97262306a36Sopenharmony_ci kfree(urb->transfer_buffer); 97362306a36Sopenharmony_ci} 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_cistatic int garmin_write_bulk(struct usb_serial_port *port, 97762306a36Sopenharmony_ci const unsigned char *buf, int count, 97862306a36Sopenharmony_ci int dismiss_ack) 97962306a36Sopenharmony_ci{ 98062306a36Sopenharmony_ci unsigned long flags; 98162306a36Sopenharmony_ci struct usb_serial *serial = port->serial; 98262306a36Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 98362306a36Sopenharmony_ci struct urb *urb; 98462306a36Sopenharmony_ci unsigned char *buffer; 98562306a36Sopenharmony_ci int status; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 98862306a36Sopenharmony_ci garmin_data_p->flags &= ~FLAGS_DROP_DATA; 98962306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci buffer = kmemdup(buf, count, GFP_ATOMIC); 99262306a36Sopenharmony_ci if (!buffer) 99362306a36Sopenharmony_ci return -ENOMEM; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_ATOMIC); 99662306a36Sopenharmony_ci if (!urb) { 99762306a36Sopenharmony_ci kfree(buffer); 99862306a36Sopenharmony_ci return -ENOMEM; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci usb_serial_debug_data(&port->dev, __func__, count, buffer); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci usb_fill_bulk_urb(urb, serial->dev, 100462306a36Sopenharmony_ci usb_sndbulkpipe(serial->dev, 100562306a36Sopenharmony_ci port->bulk_out_endpointAddress), 100662306a36Sopenharmony_ci buffer, count, 100762306a36Sopenharmony_ci garmin_write_bulk_callback, 100862306a36Sopenharmony_ci dismiss_ack ? NULL : port); 100962306a36Sopenharmony_ci urb->transfer_flags |= URB_ZERO_PACKET; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (getLayerId(buffer) == GARMIN_LAYERID_APPL) { 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 101462306a36Sopenharmony_ci garmin_data_p->flags |= APP_REQ_SEEN; 101562306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { 101862306a36Sopenharmony_ci pkt_clear(garmin_data_p); 101962306a36Sopenharmony_ci garmin_data_p->state = STATE_GSP_WAIT_DATA; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci } 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci /* send it down the pipe */ 102462306a36Sopenharmony_ci usb_anchor_urb(urb, &garmin_data_p->write_urbs); 102562306a36Sopenharmony_ci status = usb_submit_urb(urb, GFP_ATOMIC); 102662306a36Sopenharmony_ci if (status) { 102762306a36Sopenharmony_ci dev_err(&port->dev, 102862306a36Sopenharmony_ci "%s - usb_submit_urb(write bulk) failed with status = %d\n", 102962306a36Sopenharmony_ci __func__, status); 103062306a36Sopenharmony_ci count = status; 103162306a36Sopenharmony_ci usb_unanchor_urb(urb); 103262306a36Sopenharmony_ci kfree(buffer); 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci /* we are done with this urb, so let the host driver 103662306a36Sopenharmony_ci * really free it when it is finished with it */ 103762306a36Sopenharmony_ci usb_free_urb(urb); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci return count; 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic int garmin_write(struct tty_struct *tty, struct usb_serial_port *port, 104362306a36Sopenharmony_ci const unsigned char *buf, int count) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci struct device *dev = &port->dev; 104662306a36Sopenharmony_ci int pktid, pktsiz, len; 104762306a36Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 104862306a36Sopenharmony_ci __le32 *privpkt = (__le32 *)garmin_data_p->privpkt; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci usb_serial_debug_data(dev, __func__, count, buf); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (garmin_data_p->state == STATE_RESET) 105362306a36Sopenharmony_ci return -EIO; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci /* check for our private packets */ 105662306a36Sopenharmony_ci if (count >= GARMIN_PKTHDR_LENGTH) { 105762306a36Sopenharmony_ci len = PRIVPKTSIZ; 105862306a36Sopenharmony_ci if (count < len) 105962306a36Sopenharmony_ci len = count; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci memcpy(garmin_data_p->privpkt, buf, len); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci pktsiz = getDataLength(garmin_data_p->privpkt); 106462306a36Sopenharmony_ci pktid = getPacketId(garmin_data_p->privpkt); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci if (count == (GARMIN_PKTHDR_LENGTH + pktsiz) && 106762306a36Sopenharmony_ci getLayerId(garmin_data_p->privpkt) == 106862306a36Sopenharmony_ci GARMIN_LAYERID_PRIVATE) { 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci dev_dbg(dev, "%s - processing private request %d\n", 107162306a36Sopenharmony_ci __func__, pktid); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci /* drop all unfinished transfers */ 107462306a36Sopenharmony_ci garmin_clear(garmin_data_p); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci switch (pktid) { 107762306a36Sopenharmony_ci case PRIV_PKTID_SET_MODE: 107862306a36Sopenharmony_ci if (pktsiz != 4) 107962306a36Sopenharmony_ci return -EINVPKT; 108062306a36Sopenharmony_ci garmin_data_p->mode = __le32_to_cpu(privpkt[3]); 108162306a36Sopenharmony_ci dev_dbg(dev, "%s - mode set to %d\n", 108262306a36Sopenharmony_ci __func__, garmin_data_p->mode); 108362306a36Sopenharmony_ci break; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci case PRIV_PKTID_INFO_REQ: 108662306a36Sopenharmony_ci priv_status_resp(port); 108762306a36Sopenharmony_ci break; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci case PRIV_PKTID_RESET_REQ: 109062306a36Sopenharmony_ci process_resetdev_request(port); 109162306a36Sopenharmony_ci break; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci case PRIV_PKTID_SET_DEF_MODE: 109462306a36Sopenharmony_ci if (pktsiz != 4) 109562306a36Sopenharmony_ci return -EINVPKT; 109662306a36Sopenharmony_ci initial_mode = __le32_to_cpu(privpkt[3]); 109762306a36Sopenharmony_ci dev_dbg(dev, "%s - initial_mode set to %d\n", 109862306a36Sopenharmony_ci __func__, 109962306a36Sopenharmony_ci garmin_data_p->mode); 110062306a36Sopenharmony_ci break; 110162306a36Sopenharmony_ci } 110262306a36Sopenharmony_ci return count; 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { 110762306a36Sopenharmony_ci return gsp_receive(garmin_data_p, buf, count); 110862306a36Sopenharmony_ci } else { /* MODE_NATIVE */ 110962306a36Sopenharmony_ci return nat_receive(garmin_data_p, buf, count); 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cistatic unsigned int garmin_write_room(struct tty_struct *tty) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 111762306a36Sopenharmony_ci /* 111862306a36Sopenharmony_ci * Report back the bytes currently available in the output buffer. 111962306a36Sopenharmony_ci */ 112062306a36Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 112162306a36Sopenharmony_ci return GPS_OUT_BUFSIZ-garmin_data_p->outsize; 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cistatic void garmin_read_process(struct garmin_data *garmin_data_p, 112662306a36Sopenharmony_ci unsigned char *data, unsigned data_length, 112762306a36Sopenharmony_ci int bulk_data) 112862306a36Sopenharmony_ci{ 112962306a36Sopenharmony_ci unsigned long flags; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci if (garmin_data_p->flags & FLAGS_DROP_DATA) { 113262306a36Sopenharmony_ci /* abort-transfer cmd is active */ 113362306a36Sopenharmony_ci dev_dbg(&garmin_data_p->port->dev, "%s - pkt dropped\n", __func__); 113462306a36Sopenharmony_ci } else if (garmin_data_p->state != STATE_DISCONNECTED && 113562306a36Sopenharmony_ci garmin_data_p->state != STATE_RESET) { 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci /* if throttling is active or postprecessing is required 113862306a36Sopenharmony_ci put the received data in the input queue, otherwise 113962306a36Sopenharmony_ci send it directly to the tty port */ 114062306a36Sopenharmony_ci if (garmin_data_p->flags & FLAGS_QUEUING) { 114162306a36Sopenharmony_ci pkt_add(garmin_data_p, data, data_length); 114262306a36Sopenharmony_ci } else if (bulk_data || (data_length >= sizeof(u32) && 114362306a36Sopenharmony_ci getLayerId(data) == GARMIN_LAYERID_APPL)) { 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 114662306a36Sopenharmony_ci garmin_data_p->flags |= APP_RESP_SEEN; 114762306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { 115062306a36Sopenharmony_ci pkt_add(garmin_data_p, data, data_length); 115162306a36Sopenharmony_ci } else { 115262306a36Sopenharmony_ci send_to_tty(garmin_data_p->port, data, 115362306a36Sopenharmony_ci data_length); 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci /* ignore system layer packets ... */ 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci} 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_cistatic void garmin_read_bulk_callback(struct urb *urb) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci unsigned long flags; 116462306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 116562306a36Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 116662306a36Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 116762306a36Sopenharmony_ci int status = urb->status; 116862306a36Sopenharmony_ci int retval; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci if (status) { 117162306a36Sopenharmony_ci dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n", 117262306a36Sopenharmony_ci __func__, status); 117362306a36Sopenharmony_ci return; 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci garmin_read_process(garmin_data_p, data, urb->actual_length, 1); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci if (urb->actual_length == 0 && 118162306a36Sopenharmony_ci (garmin_data_p->flags & FLAGS_BULK_IN_RESTART) != 0) { 118262306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 118362306a36Sopenharmony_ci garmin_data_p->flags &= ~FLAGS_BULK_IN_RESTART; 118462306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 118562306a36Sopenharmony_ci retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); 118662306a36Sopenharmony_ci if (retval) 118762306a36Sopenharmony_ci dev_err(&port->dev, 118862306a36Sopenharmony_ci "%s - failed resubmitting read urb, error %d\n", 118962306a36Sopenharmony_ci __func__, retval); 119062306a36Sopenharmony_ci } else if (urb->actual_length > 0) { 119162306a36Sopenharmony_ci /* Continue trying to read until nothing more is received */ 119262306a36Sopenharmony_ci if ((garmin_data_p->flags & FLAGS_THROTTLED) == 0) { 119362306a36Sopenharmony_ci retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); 119462306a36Sopenharmony_ci if (retval) 119562306a36Sopenharmony_ci dev_err(&port->dev, 119662306a36Sopenharmony_ci "%s - failed resubmitting read urb, error %d\n", 119762306a36Sopenharmony_ci __func__, retval); 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci } else { 120062306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - end of bulk data\n", __func__); 120162306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 120262306a36Sopenharmony_ci garmin_data_p->flags &= ~FLAGS_BULK_IN_ACTIVE; 120362306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci} 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_cistatic void garmin_read_int_callback(struct urb *urb) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci unsigned long flags; 121162306a36Sopenharmony_ci int retval; 121262306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 121362306a36Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 121462306a36Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 121562306a36Sopenharmony_ci int status = urb->status; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci switch (status) { 121862306a36Sopenharmony_ci case 0: 121962306a36Sopenharmony_ci /* success */ 122062306a36Sopenharmony_ci break; 122162306a36Sopenharmony_ci case -ECONNRESET: 122262306a36Sopenharmony_ci case -ENOENT: 122362306a36Sopenharmony_ci case -ESHUTDOWN: 122462306a36Sopenharmony_ci /* this urb is terminated, clean up */ 122562306a36Sopenharmony_ci dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", 122662306a36Sopenharmony_ci __func__, status); 122762306a36Sopenharmony_ci return; 122862306a36Sopenharmony_ci default: 122962306a36Sopenharmony_ci dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", 123062306a36Sopenharmony_ci __func__, status); 123162306a36Sopenharmony_ci return; 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci usb_serial_debug_data(&port->dev, __func__, urb->actual_length, 123562306a36Sopenharmony_ci urb->transfer_buffer); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci if (urb->actual_length == sizeof(GARMIN_BULK_IN_AVAIL_REPLY) && 123862306a36Sopenharmony_ci memcmp(data, GARMIN_BULK_IN_AVAIL_REPLY, 123962306a36Sopenharmony_ci sizeof(GARMIN_BULK_IN_AVAIL_REPLY)) == 0) { 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - bulk data available.\n", __func__); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci if ((garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE) == 0) { 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* bulk data available */ 124662306a36Sopenharmony_ci retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); 124762306a36Sopenharmony_ci if (retval) { 124862306a36Sopenharmony_ci dev_err(&port->dev, 124962306a36Sopenharmony_ci "%s - failed submitting read urb, error %d\n", 125062306a36Sopenharmony_ci __func__, retval); 125162306a36Sopenharmony_ci } else { 125262306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 125362306a36Sopenharmony_ci garmin_data_p->flags |= FLAGS_BULK_IN_ACTIVE; 125462306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, 125562306a36Sopenharmony_ci flags); 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci } else { 125862306a36Sopenharmony_ci /* bulk-in transfer still active */ 125962306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 126062306a36Sopenharmony_ci garmin_data_p->flags |= FLAGS_BULK_IN_RESTART; 126162306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci } else if (urb->actual_length == (4+sizeof(GARMIN_START_SESSION_REPLY)) 126562306a36Sopenharmony_ci && memcmp(data, GARMIN_START_SESSION_REPLY, 126662306a36Sopenharmony_ci sizeof(GARMIN_START_SESSION_REPLY)) == 0) { 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 126962306a36Sopenharmony_ci garmin_data_p->flags |= FLAGS_SESSION_REPLY1_SEEN; 127062306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci /* save the serial number */ 127362306a36Sopenharmony_ci garmin_data_p->serial_num = __le32_to_cpup( 127462306a36Sopenharmony_ci (__le32 *)(data+GARMIN_PKTHDR_LENGTH)); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - start-of-session reply seen - serial %u.\n", 127762306a36Sopenharmony_ci __func__, garmin_data_p->serial_num); 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci garmin_read_process(garmin_data_p, data, urb->actual_length, 0); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci retval = usb_submit_urb(urb, GFP_ATOMIC); 128362306a36Sopenharmony_ci if (retval) 128462306a36Sopenharmony_ci dev_err(&urb->dev->dev, 128562306a36Sopenharmony_ci "%s - Error %d submitting interrupt urb\n", 128662306a36Sopenharmony_ci __func__, retval); 128762306a36Sopenharmony_ci} 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci/* 129162306a36Sopenharmony_ci * Sends the next queued packt to the tty port (garmin native mode only) 129262306a36Sopenharmony_ci * and then sets a timer to call itself again until all queued data 129362306a36Sopenharmony_ci * is sent. 129462306a36Sopenharmony_ci */ 129562306a36Sopenharmony_cistatic int garmin_flush_queue(struct garmin_data *garmin_data_p) 129662306a36Sopenharmony_ci{ 129762306a36Sopenharmony_ci unsigned long flags; 129862306a36Sopenharmony_ci struct garmin_packet *pkt; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci if ((garmin_data_p->flags & FLAGS_THROTTLED) == 0) { 130162306a36Sopenharmony_ci pkt = pkt_pop(garmin_data_p); 130262306a36Sopenharmony_ci if (pkt != NULL) { 130362306a36Sopenharmony_ci send_to_tty(garmin_data_p->port, pkt->data, pkt->size); 130462306a36Sopenharmony_ci kfree(pkt); 130562306a36Sopenharmony_ci mod_timer(&garmin_data_p->timer, (1)+jiffies); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci } else { 130862306a36Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 130962306a36Sopenharmony_ci garmin_data_p->flags &= ~FLAGS_QUEUING; 131062306a36Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci return 0; 131462306a36Sopenharmony_ci} 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_cistatic void garmin_throttle(struct tty_struct *tty) 131862306a36Sopenharmony_ci{ 131962306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 132062306a36Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci /* set flag, data received will be put into a queue 132362306a36Sopenharmony_ci for later processing */ 132462306a36Sopenharmony_ci spin_lock_irq(&garmin_data_p->lock); 132562306a36Sopenharmony_ci garmin_data_p->flags |= FLAGS_QUEUING|FLAGS_THROTTLED; 132662306a36Sopenharmony_ci spin_unlock_irq(&garmin_data_p->lock); 132762306a36Sopenharmony_ci} 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_cistatic void garmin_unthrottle(struct tty_struct *tty) 133162306a36Sopenharmony_ci{ 133262306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 133362306a36Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 133462306a36Sopenharmony_ci int status; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci spin_lock_irq(&garmin_data_p->lock); 133762306a36Sopenharmony_ci garmin_data_p->flags &= ~FLAGS_THROTTLED; 133862306a36Sopenharmony_ci spin_unlock_irq(&garmin_data_p->lock); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci /* in native mode send queued data to tty, in 134162306a36Sopenharmony_ci serial mode nothing needs to be done here */ 134262306a36Sopenharmony_ci if (garmin_data_p->mode == MODE_NATIVE) 134362306a36Sopenharmony_ci garmin_flush_queue(garmin_data_p); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if ((garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE) != 0) { 134662306a36Sopenharmony_ci status = usb_submit_urb(port->read_urb, GFP_KERNEL); 134762306a36Sopenharmony_ci if (status) 134862306a36Sopenharmony_ci dev_err(&port->dev, 134962306a36Sopenharmony_ci "%s - failed resubmitting read urb, error %d\n", 135062306a36Sopenharmony_ci __func__, status); 135162306a36Sopenharmony_ci } 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci/* 135562306a36Sopenharmony_ci * The timer is currently only used to send queued packets to 135662306a36Sopenharmony_ci * the tty in cases where the protocol provides no own handshaking 135762306a36Sopenharmony_ci * to initiate the transfer. 135862306a36Sopenharmony_ci */ 135962306a36Sopenharmony_cistatic void timeout_handler(struct timer_list *t) 136062306a36Sopenharmony_ci{ 136162306a36Sopenharmony_ci struct garmin_data *garmin_data_p = from_timer(garmin_data_p, t, timer); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci /* send the next queued packet to the tty port */ 136462306a36Sopenharmony_ci if (garmin_data_p->mode == MODE_NATIVE) 136562306a36Sopenharmony_ci if (garmin_data_p->flags & FLAGS_QUEUING) 136662306a36Sopenharmony_ci garmin_flush_queue(garmin_data_p); 136762306a36Sopenharmony_ci} 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_cistatic int garmin_port_probe(struct usb_serial_port *port) 137262306a36Sopenharmony_ci{ 137362306a36Sopenharmony_ci int status; 137462306a36Sopenharmony_ci struct garmin_data *garmin_data_p; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL); 137762306a36Sopenharmony_ci if (!garmin_data_p) 137862306a36Sopenharmony_ci return -ENOMEM; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci timer_setup(&garmin_data_p->timer, timeout_handler, 0); 138162306a36Sopenharmony_ci spin_lock_init(&garmin_data_p->lock); 138262306a36Sopenharmony_ci INIT_LIST_HEAD(&garmin_data_p->pktlist); 138362306a36Sopenharmony_ci garmin_data_p->port = port; 138462306a36Sopenharmony_ci garmin_data_p->state = 0; 138562306a36Sopenharmony_ci garmin_data_p->flags = 0; 138662306a36Sopenharmony_ci garmin_data_p->count = 0; 138762306a36Sopenharmony_ci init_usb_anchor(&garmin_data_p->write_urbs); 138862306a36Sopenharmony_ci usb_set_serial_port_data(port, garmin_data_p); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci status = garmin_init_session(port); 139162306a36Sopenharmony_ci if (status) 139262306a36Sopenharmony_ci goto err_free; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci return 0; 139562306a36Sopenharmony_cierr_free: 139662306a36Sopenharmony_ci kfree(garmin_data_p); 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci return status; 139962306a36Sopenharmony_ci} 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_cistatic void garmin_port_remove(struct usb_serial_port *port) 140362306a36Sopenharmony_ci{ 140462306a36Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci usb_kill_anchored_urbs(&garmin_data_p->write_urbs); 140762306a36Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 140862306a36Sopenharmony_ci timer_shutdown_sync(&garmin_data_p->timer); 140962306a36Sopenharmony_ci kfree(garmin_data_p); 141062306a36Sopenharmony_ci} 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci/* All of the device info needed */ 141462306a36Sopenharmony_cistatic struct usb_serial_driver garmin_device = { 141562306a36Sopenharmony_ci .driver = { 141662306a36Sopenharmony_ci .owner = THIS_MODULE, 141762306a36Sopenharmony_ci .name = "garmin_gps", 141862306a36Sopenharmony_ci }, 141962306a36Sopenharmony_ci .description = "Garmin GPS usb/tty", 142062306a36Sopenharmony_ci .id_table = id_table, 142162306a36Sopenharmony_ci .num_ports = 1, 142262306a36Sopenharmony_ci .open = garmin_open, 142362306a36Sopenharmony_ci .close = garmin_close, 142462306a36Sopenharmony_ci .throttle = garmin_throttle, 142562306a36Sopenharmony_ci .unthrottle = garmin_unthrottle, 142662306a36Sopenharmony_ci .port_probe = garmin_port_probe, 142762306a36Sopenharmony_ci .port_remove = garmin_port_remove, 142862306a36Sopenharmony_ci .write = garmin_write, 142962306a36Sopenharmony_ci .write_room = garmin_write_room, 143062306a36Sopenharmony_ci .write_bulk_callback = garmin_write_bulk_callback, 143162306a36Sopenharmony_ci .read_bulk_callback = garmin_read_bulk_callback, 143262306a36Sopenharmony_ci .read_int_callback = garmin_read_int_callback, 143362306a36Sopenharmony_ci}; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 143662306a36Sopenharmony_ci &garmin_device, NULL 143762306a36Sopenharmony_ci}; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 144262306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 144362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_cimodule_param(initial_mode, int, 0444); 144662306a36Sopenharmony_ciMODULE_PARM_DESC(initial_mode, "Initial mode"); 1447