18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Garmin GPS driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2011 Hermann Kneissel herkne@gmx.de 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * The latest version of the driver can be found at 88c2ecf20Sopenharmony_ci * http://sourceforge.net/projects/garmin-gps/ 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This driver has been derived from v2.1 of the visor driver. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/timer.h> 178c2ecf20Sopenharmony_ci#include <linux/tty.h> 188c2ecf20Sopenharmony_ci#include <linux/tty_driver.h> 198c2ecf20Sopenharmony_ci#include <linux/tty_flip.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 228c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 238c2ecf20Sopenharmony_ci#include <linux/atomic.h> 248c2ecf20Sopenharmony_ci#include <linux/usb.h> 258c2ecf20Sopenharmony_ci#include <linux/usb/serial.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* the mode to be set when the port ist opened */ 288c2ecf20Sopenharmony_cistatic int initial_mode = 1; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define GARMIN_VENDOR_ID 0x091E 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * Version Information 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define VERSION_MAJOR 0 378c2ecf20Sopenharmony_ci#define VERSION_MINOR 36 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define _STR(s) #s 408c2ecf20Sopenharmony_ci#define _DRIVER_VERSION(a, b) "v" _STR(a) "." _STR(b) 418c2ecf20Sopenharmony_ci#define DRIVER_VERSION _DRIVER_VERSION(VERSION_MAJOR, VERSION_MINOR) 428c2ecf20Sopenharmony_ci#define DRIVER_AUTHOR "hermann kneissel" 438c2ecf20Sopenharmony_ci#define DRIVER_DESC "garmin gps driver" 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* error codes returned by the driver */ 468c2ecf20Sopenharmony_ci#define EINVPKT 1000 /* invalid packet structure */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* size of the header of a packet using the usb protocol */ 508c2ecf20Sopenharmony_ci#define GARMIN_PKTHDR_LENGTH 12 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* max. possible size of a packet using the serial protocol */ 538c2ecf20Sopenharmony_ci#define MAX_SERIAL_PKT_SIZ (3 + 255 + 3) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* max. possible size of a packet with worst case stuffing */ 568c2ecf20Sopenharmony_ci#define MAX_SERIAL_PKT_SIZ_STUFFED (MAX_SERIAL_PKT_SIZ + 256) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* size of a buffer able to hold a complete (no stuffing) packet 598c2ecf20Sopenharmony_ci * (the document protocol does not contain packets with a larger 608c2ecf20Sopenharmony_ci * size, but in theory a packet may be 64k+12 bytes - if in 618c2ecf20Sopenharmony_ci * later protocol versions larger packet sizes occur, this value 628c2ecf20Sopenharmony_ci * should be increased accordingly, so the input buffer is always 638c2ecf20Sopenharmony_ci * large enough the store a complete packet inclusive header) */ 648c2ecf20Sopenharmony_ci#define GPS_IN_BUFSIZ (GARMIN_PKTHDR_LENGTH+MAX_SERIAL_PKT_SIZ) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* size of a buffer able to hold a complete (incl. stuffing) packet */ 678c2ecf20Sopenharmony_ci#define GPS_OUT_BUFSIZ (GARMIN_PKTHDR_LENGTH+MAX_SERIAL_PKT_SIZ_STUFFED) 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* where to place the packet id of a serial packet, so we can 708c2ecf20Sopenharmony_ci * prepend the usb-packet header without the need to move the 718c2ecf20Sopenharmony_ci * packets data */ 728c2ecf20Sopenharmony_ci#define GSP_INITIAL_OFFSET (GARMIN_PKTHDR_LENGTH-2) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* max. size of incoming private packets (header+1 param) */ 758c2ecf20Sopenharmony_ci#define PRIVPKTSIZ (GARMIN_PKTHDR_LENGTH+4) 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define GARMIN_LAYERID_TRANSPORT 0 788c2ecf20Sopenharmony_ci#define GARMIN_LAYERID_APPL 20 798c2ecf20Sopenharmony_ci/* our own layer-id to use for some control mechanisms */ 808c2ecf20Sopenharmony_ci#define GARMIN_LAYERID_PRIVATE 0x01106E4B 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define GARMIN_PKTID_PVT_DATA 51 838c2ecf20Sopenharmony_ci#define GARMIN_PKTID_L001_COMMAND_DATA 10 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#define CMND_ABORT_TRANSFER 0 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* packet ids used in private layer */ 888c2ecf20Sopenharmony_ci#define PRIV_PKTID_SET_DEBUG 1 898c2ecf20Sopenharmony_ci#define PRIV_PKTID_SET_MODE 2 908c2ecf20Sopenharmony_ci#define PRIV_PKTID_INFO_REQ 3 918c2ecf20Sopenharmony_ci#define PRIV_PKTID_INFO_RESP 4 928c2ecf20Sopenharmony_ci#define PRIV_PKTID_RESET_REQ 5 938c2ecf20Sopenharmony_ci#define PRIV_PKTID_SET_DEF_MODE 6 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define ETX 0x03 978c2ecf20Sopenharmony_ci#define DLE 0x10 988c2ecf20Sopenharmony_ci#define ACK 0x06 998c2ecf20Sopenharmony_ci#define NAK 0x15 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/* structure used to queue incoming packets */ 1028c2ecf20Sopenharmony_cistruct garmin_packet { 1038c2ecf20Sopenharmony_ci struct list_head list; 1048c2ecf20Sopenharmony_ci int seq; 1058c2ecf20Sopenharmony_ci /* the real size of the data array, always > 0 */ 1068c2ecf20Sopenharmony_ci int size; 1078c2ecf20Sopenharmony_ci __u8 data[]; 1088c2ecf20Sopenharmony_ci}; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* structure used to keep the current state of the driver */ 1118c2ecf20Sopenharmony_cistruct garmin_data { 1128c2ecf20Sopenharmony_ci __u8 state; 1138c2ecf20Sopenharmony_ci __u16 flags; 1148c2ecf20Sopenharmony_ci __u8 mode; 1158c2ecf20Sopenharmony_ci __u8 count; 1168c2ecf20Sopenharmony_ci __u8 pkt_id; 1178c2ecf20Sopenharmony_ci __u32 serial_num; 1188c2ecf20Sopenharmony_ci struct timer_list timer; 1198c2ecf20Sopenharmony_ci struct usb_serial_port *port; 1208c2ecf20Sopenharmony_ci int seq_counter; 1218c2ecf20Sopenharmony_ci int insize; 1228c2ecf20Sopenharmony_ci int outsize; 1238c2ecf20Sopenharmony_ci __u8 inbuffer [GPS_IN_BUFSIZ]; /* tty -> usb */ 1248c2ecf20Sopenharmony_ci __u8 outbuffer[GPS_OUT_BUFSIZ]; /* usb -> tty */ 1258c2ecf20Sopenharmony_ci __u8 privpkt[4*6]; 1268c2ecf20Sopenharmony_ci spinlock_t lock; 1278c2ecf20Sopenharmony_ci struct list_head pktlist; 1288c2ecf20Sopenharmony_ci struct usb_anchor write_urbs; 1298c2ecf20Sopenharmony_ci}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci#define STATE_NEW 0 1338c2ecf20Sopenharmony_ci#define STATE_INITIAL_DELAY 1 1348c2ecf20Sopenharmony_ci#define STATE_TIMEOUT 2 1358c2ecf20Sopenharmony_ci#define STATE_SESSION_REQ1 3 1368c2ecf20Sopenharmony_ci#define STATE_SESSION_REQ2 4 1378c2ecf20Sopenharmony_ci#define STATE_ACTIVE 5 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci#define STATE_RESET 8 1408c2ecf20Sopenharmony_ci#define STATE_DISCONNECTED 9 1418c2ecf20Sopenharmony_ci#define STATE_WAIT_TTY_ACK 10 1428c2ecf20Sopenharmony_ci#define STATE_GSP_WAIT_DATA 11 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci#define MODE_NATIVE 0 1458c2ecf20Sopenharmony_ci#define MODE_GARMIN_SERIAL 1 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/* Flags used in garmin_data.flags: */ 1488c2ecf20Sopenharmony_ci#define FLAGS_SESSION_REPLY_MASK 0x00C0 1498c2ecf20Sopenharmony_ci#define FLAGS_SESSION_REPLY1_SEEN 0x0080 1508c2ecf20Sopenharmony_ci#define FLAGS_SESSION_REPLY2_SEEN 0x0040 1518c2ecf20Sopenharmony_ci#define FLAGS_BULK_IN_ACTIVE 0x0020 1528c2ecf20Sopenharmony_ci#define FLAGS_BULK_IN_RESTART 0x0010 1538c2ecf20Sopenharmony_ci#define FLAGS_THROTTLED 0x0008 1548c2ecf20Sopenharmony_ci#define APP_REQ_SEEN 0x0004 1558c2ecf20Sopenharmony_ci#define APP_RESP_SEEN 0x0002 1568c2ecf20Sopenharmony_ci#define CLEAR_HALT_REQUIRED 0x0001 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci#define FLAGS_QUEUING 0x0100 1598c2ecf20Sopenharmony_ci#define FLAGS_DROP_DATA 0x0800 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci#define FLAGS_GSP_SKIP 0x1000 1628c2ecf20Sopenharmony_ci#define FLAGS_GSP_DLESEEN 0x2000 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* function prototypes */ 1708c2ecf20Sopenharmony_cistatic int gsp_next_packet(struct garmin_data *garmin_data_p); 1718c2ecf20Sopenharmony_cistatic int garmin_write_bulk(struct usb_serial_port *port, 1728c2ecf20Sopenharmony_ci const unsigned char *buf, int count, 1738c2ecf20Sopenharmony_ci int dismiss_ack); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* some special packets to be send or received */ 1768c2ecf20Sopenharmony_cistatic unsigned char const GARMIN_START_SESSION_REQ[] 1778c2ecf20Sopenharmony_ci = { 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0 }; 1788c2ecf20Sopenharmony_cistatic unsigned char const GARMIN_START_SESSION_REPLY[] 1798c2ecf20Sopenharmony_ci = { 0, 0, 0, 0, 6, 0, 0, 0, 4, 0, 0, 0 }; 1808c2ecf20Sopenharmony_cistatic unsigned char const GARMIN_BULK_IN_AVAIL_REPLY[] 1818c2ecf20Sopenharmony_ci = { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 }; 1828c2ecf20Sopenharmony_cistatic unsigned char const GARMIN_STOP_TRANSFER_REQ[] 1838c2ecf20Sopenharmony_ci = { 20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 0, 0 }; 1848c2ecf20Sopenharmony_cistatic unsigned char const GARMIN_STOP_TRANSFER_REQ_V2[] 1858c2ecf20Sopenharmony_ci = { 20, 0, 0, 0, 10, 0, 0, 0, 1, 0, 0, 0, 0 }; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* packets currently unused, left as documentation */ 1888c2ecf20Sopenharmony_ci#if 0 1898c2ecf20Sopenharmony_cistatic unsigned char const GARMIN_APP_LAYER_REPLY[] 1908c2ecf20Sopenharmony_ci = { 0x14, 0, 0, 0 }; 1918c2ecf20Sopenharmony_cistatic unsigned char const GARMIN_START_PVT_REQ[] 1928c2ecf20Sopenharmony_ci = { 20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 49, 0 }; 1938c2ecf20Sopenharmony_cistatic unsigned char const GARMIN_STOP_PVT_REQ[] 1948c2ecf20Sopenharmony_ci = { 20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 50, 0 }; 1958c2ecf20Sopenharmony_cistatic unsigned char const PRIVATE_REQ[] 1968c2ecf20Sopenharmony_ci = { 0x4B, 0x6E, 0x10, 0x01, 0xFF, 0, 0, 0, 0xFF, 0, 0, 0 }; 1978c2ecf20Sopenharmony_ci#endif 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic const struct usb_device_id id_table[] = { 2018c2ecf20Sopenharmony_ci /* the same device id seems to be used by all 2028c2ecf20Sopenharmony_ci usb enabled GPS devices */ 2038c2ecf20Sopenharmony_ci { USB_DEVICE(GARMIN_VENDOR_ID, 3) }, 2048c2ecf20Sopenharmony_ci { } /* Terminating entry */ 2058c2ecf20Sopenharmony_ci}; 2068c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic inline int getLayerId(const __u8 *usbPacket) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci return __le32_to_cpup((__le32 *)(usbPacket)); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic inline int getPacketId(const __u8 *usbPacket) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci return __le32_to_cpup((__le32 *)(usbPacket+4)); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic inline int getDataLength(const __u8 *usbPacket) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci return __le32_to_cpup((__le32 *)(usbPacket+8)); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci/* 2268c2ecf20Sopenharmony_ci * check if the usb-packet in buf contains an abort-transfer command. 2278c2ecf20Sopenharmony_ci * (if yes, all queued data will be dropped) 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_cistatic inline int isAbortTrfCmnd(const unsigned char *buf) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci if (memcmp(buf, GARMIN_STOP_TRANSFER_REQ, 2328c2ecf20Sopenharmony_ci sizeof(GARMIN_STOP_TRANSFER_REQ)) == 0 || 2338c2ecf20Sopenharmony_ci memcmp(buf, GARMIN_STOP_TRANSFER_REQ_V2, 2348c2ecf20Sopenharmony_ci sizeof(GARMIN_STOP_TRANSFER_REQ_V2)) == 0) 2358c2ecf20Sopenharmony_ci return 1; 2368c2ecf20Sopenharmony_ci else 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic void send_to_tty(struct usb_serial_port *port, 2438c2ecf20Sopenharmony_ci char *data, unsigned int actual_length) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci if (actual_length) { 2468c2ecf20Sopenharmony_ci usb_serial_debug_data(&port->dev, __func__, actual_length, data); 2478c2ecf20Sopenharmony_ci tty_insert_flip_string(&port->port, data, actual_length); 2488c2ecf20Sopenharmony_ci tty_flip_buffer_push(&port->port); 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/****************************************************************************** 2548c2ecf20Sopenharmony_ci * packet queue handling 2558c2ecf20Sopenharmony_ci ******************************************************************************/ 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/* 2588c2ecf20Sopenharmony_ci * queue a received (usb-)packet for later processing 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_cistatic int pkt_add(struct garmin_data *garmin_data_p, 2618c2ecf20Sopenharmony_ci unsigned char *data, unsigned int data_length) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci int state = 0; 2648c2ecf20Sopenharmony_ci int result = 0; 2658c2ecf20Sopenharmony_ci unsigned long flags; 2668c2ecf20Sopenharmony_ci struct garmin_packet *pkt; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* process only packets containing data ... */ 2698c2ecf20Sopenharmony_ci if (data_length) { 2708c2ecf20Sopenharmony_ci pkt = kmalloc(struct_size(pkt, data, data_length), GFP_ATOMIC); 2718c2ecf20Sopenharmony_ci if (!pkt) 2728c2ecf20Sopenharmony_ci return 0; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci pkt->size = data_length; 2758c2ecf20Sopenharmony_ci memcpy(pkt->data, data, data_length); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 2788c2ecf20Sopenharmony_ci garmin_data_p->flags |= FLAGS_QUEUING; 2798c2ecf20Sopenharmony_ci result = list_empty(&garmin_data_p->pktlist); 2808c2ecf20Sopenharmony_ci pkt->seq = garmin_data_p->seq_counter++; 2818c2ecf20Sopenharmony_ci list_add_tail(&pkt->list, &garmin_data_p->pktlist); 2828c2ecf20Sopenharmony_ci state = garmin_data_p->state; 2838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci dev_dbg(&garmin_data_p->port->dev, 2868c2ecf20Sopenharmony_ci "%s - added: pkt: %d - %d bytes\n", __func__, 2878c2ecf20Sopenharmony_ci pkt->seq, data_length); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* in serial mode, if someone is waiting for data from 2908c2ecf20Sopenharmony_ci the device, convert and send the next packet to tty. */ 2918c2ecf20Sopenharmony_ci if (result && (state == STATE_GSP_WAIT_DATA)) 2928c2ecf20Sopenharmony_ci gsp_next_packet(garmin_data_p); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci return result; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/* get the next pending packet */ 2998c2ecf20Sopenharmony_cistatic struct garmin_packet *pkt_pop(struct garmin_data *garmin_data_p) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci unsigned long flags; 3028c2ecf20Sopenharmony_ci struct garmin_packet *result = NULL; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 3058c2ecf20Sopenharmony_ci if (!list_empty(&garmin_data_p->pktlist)) { 3068c2ecf20Sopenharmony_ci result = (struct garmin_packet *)garmin_data_p->pktlist.next; 3078c2ecf20Sopenharmony_ci list_del(&result->list); 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 3108c2ecf20Sopenharmony_ci return result; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci/* free up all queued data */ 3158c2ecf20Sopenharmony_cistatic void pkt_clear(struct garmin_data *garmin_data_p) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci unsigned long flags; 3188c2ecf20Sopenharmony_ci struct garmin_packet *result = NULL; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 3218c2ecf20Sopenharmony_ci while (!list_empty(&garmin_data_p->pktlist)) { 3228c2ecf20Sopenharmony_ci result = (struct garmin_packet *)garmin_data_p->pktlist.next; 3238c2ecf20Sopenharmony_ci list_del(&result->list); 3248c2ecf20Sopenharmony_ci kfree(result); 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci/****************************************************************************** 3318c2ecf20Sopenharmony_ci * garmin serial protocol handling handling 3328c2ecf20Sopenharmony_ci ******************************************************************************/ 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci/* send an ack packet back to the tty */ 3358c2ecf20Sopenharmony_cistatic int gsp_send_ack(struct garmin_data *garmin_data_p, __u8 pkt_id) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci __u8 pkt[10]; 3388c2ecf20Sopenharmony_ci __u8 cksum = 0; 3398c2ecf20Sopenharmony_ci __u8 *ptr = pkt; 3408c2ecf20Sopenharmony_ci unsigned l = 0; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci dev_dbg(&garmin_data_p->port->dev, "%s - pkt-id: 0x%X.\n", __func__, 3438c2ecf20Sopenharmony_ci pkt_id); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci *ptr++ = DLE; 3468c2ecf20Sopenharmony_ci *ptr++ = ACK; 3478c2ecf20Sopenharmony_ci cksum += ACK; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci *ptr++ = 2; 3508c2ecf20Sopenharmony_ci cksum += 2; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci *ptr++ = pkt_id; 3538c2ecf20Sopenharmony_ci cksum += pkt_id; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (pkt_id == DLE) 3568c2ecf20Sopenharmony_ci *ptr++ = DLE; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci *ptr++ = 0; 3598c2ecf20Sopenharmony_ci *ptr++ = (-cksum) & 0xFF; 3608c2ecf20Sopenharmony_ci *ptr++ = DLE; 3618c2ecf20Sopenharmony_ci *ptr++ = ETX; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci l = ptr-pkt; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci send_to_tty(garmin_data_p->port, pkt, l); 3668c2ecf20Sopenharmony_ci return 0; 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci/* 3728c2ecf20Sopenharmony_ci * called for a complete packet received from tty layer 3738c2ecf20Sopenharmony_ci * 3748c2ecf20Sopenharmony_ci * the complete packet (pktid ... cksum) is in garmin_data_p->inbuf starting 3758c2ecf20Sopenharmony_ci * at GSP_INITIAL_OFFSET. 3768c2ecf20Sopenharmony_ci * 3778c2ecf20Sopenharmony_ci * count - number of bytes in the input buffer including space reserved for 3788c2ecf20Sopenharmony_ci * the usb header: GSP_INITIAL_OFFSET + number of bytes in packet 3798c2ecf20Sopenharmony_ci * (including pkt-id, data-length a. cksum) 3808c2ecf20Sopenharmony_ci */ 3818c2ecf20Sopenharmony_cistatic int gsp_rec_packet(struct garmin_data *garmin_data_p, int count) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct device *dev = &garmin_data_p->port->dev; 3848c2ecf20Sopenharmony_ci unsigned long flags; 3858c2ecf20Sopenharmony_ci const __u8 *recpkt = garmin_data_p->inbuffer+GSP_INITIAL_OFFSET; 3868c2ecf20Sopenharmony_ci __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer; 3878c2ecf20Sopenharmony_ci int cksum = 0; 3888c2ecf20Sopenharmony_ci int n = 0; 3898c2ecf20Sopenharmony_ci int pktid = recpkt[0]; 3908c2ecf20Sopenharmony_ci int size = recpkt[1]; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci usb_serial_debug_data(&garmin_data_p->port->dev, __func__, 3938c2ecf20Sopenharmony_ci count-GSP_INITIAL_OFFSET, recpkt); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (size != (count-GSP_INITIAL_OFFSET-3)) { 3968c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - invalid size, expected %d bytes, got %d\n", 3978c2ecf20Sopenharmony_ci __func__, size, (count-GSP_INITIAL_OFFSET-3)); 3988c2ecf20Sopenharmony_ci return -EINVPKT; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci cksum += *recpkt++; 4028c2ecf20Sopenharmony_ci cksum += *recpkt++; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* sanity check, remove after test ... */ 4058c2ecf20Sopenharmony_ci if ((__u8 *)&(usbdata[3]) != recpkt) { 4068c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - ptr mismatch %p - %p\n", __func__, 4078c2ecf20Sopenharmony_ci &(usbdata[4]), recpkt); 4088c2ecf20Sopenharmony_ci return -EINVPKT; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci while (n < size) { 4128c2ecf20Sopenharmony_ci cksum += *recpkt++; 4138c2ecf20Sopenharmony_ci n++; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (((cksum + *recpkt) & 0xff) != 0) { 4178c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - invalid checksum, expected %02x, got %02x\n", 4188c2ecf20Sopenharmony_ci __func__, -cksum & 0xff, *recpkt); 4198c2ecf20Sopenharmony_ci return -EINVPKT; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci usbdata[0] = __cpu_to_le32(GARMIN_LAYERID_APPL); 4238c2ecf20Sopenharmony_ci usbdata[1] = __cpu_to_le32(pktid); 4248c2ecf20Sopenharmony_ci usbdata[2] = __cpu_to_le32(size); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci garmin_write_bulk(garmin_data_p->port, garmin_data_p->inbuffer, 4278c2ecf20Sopenharmony_ci GARMIN_PKTHDR_LENGTH+size, 0); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* if this was an abort-transfer command, flush all 4308c2ecf20Sopenharmony_ci queued data. */ 4318c2ecf20Sopenharmony_ci if (isAbortTrfCmnd(garmin_data_p->inbuffer)) { 4328c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 4338c2ecf20Sopenharmony_ci garmin_data_p->flags |= FLAGS_DROP_DATA; 4348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 4358c2ecf20Sopenharmony_ci pkt_clear(garmin_data_p); 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci return count; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci/* 4448c2ecf20Sopenharmony_ci * Called for data received from tty 4458c2ecf20Sopenharmony_ci * 4468c2ecf20Sopenharmony_ci * buf contains the data read, it may span more than one packet or even 4478c2ecf20Sopenharmony_ci * incomplete packets 4488c2ecf20Sopenharmony_ci * 4498c2ecf20Sopenharmony_ci * input record should be a serial-record, but it may not be complete. 4508c2ecf20Sopenharmony_ci * Copy it into our local buffer, until an etx is seen (or an error 4518c2ecf20Sopenharmony_ci * occurs). 4528c2ecf20Sopenharmony_ci * Once the record is complete, convert into a usb packet and send it 4538c2ecf20Sopenharmony_ci * to the bulk pipe, send an ack back to the tty. 4548c2ecf20Sopenharmony_ci * 4558c2ecf20Sopenharmony_ci * If the input is an ack, just send the last queued packet to the 4568c2ecf20Sopenharmony_ci * tty layer. 4578c2ecf20Sopenharmony_ci * 4588c2ecf20Sopenharmony_ci * if the input is an abort command, drop all queued data. 4598c2ecf20Sopenharmony_ci */ 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic int gsp_receive(struct garmin_data *garmin_data_p, 4628c2ecf20Sopenharmony_ci const unsigned char *buf, int count) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct device *dev = &garmin_data_p->port->dev; 4658c2ecf20Sopenharmony_ci unsigned long flags; 4668c2ecf20Sopenharmony_ci int offs = 0; 4678c2ecf20Sopenharmony_ci int ack_or_nak_seen = 0; 4688c2ecf20Sopenharmony_ci __u8 *dest; 4698c2ecf20Sopenharmony_ci int size; 4708c2ecf20Sopenharmony_ci /* dleSeen: set if last byte read was a DLE */ 4718c2ecf20Sopenharmony_ci int dleSeen; 4728c2ecf20Sopenharmony_ci /* skip: if set, skip incoming data until possible start of 4738c2ecf20Sopenharmony_ci * new packet 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_ci int skip; 4768c2ecf20Sopenharmony_ci __u8 data; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 4798c2ecf20Sopenharmony_ci dest = garmin_data_p->inbuffer; 4808c2ecf20Sopenharmony_ci size = garmin_data_p->insize; 4818c2ecf20Sopenharmony_ci dleSeen = garmin_data_p->flags & FLAGS_GSP_DLESEEN; 4828c2ecf20Sopenharmony_ci skip = garmin_data_p->flags & FLAGS_GSP_SKIP; 4838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* dev_dbg(dev, "%s - dle=%d skip=%d size=%d count=%d\n", 4868c2ecf20Sopenharmony_ci __func__, dleSeen, skip, size, count); */ 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (size == 0) 4898c2ecf20Sopenharmony_ci size = GSP_INITIAL_OFFSET; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci while (offs < count) { 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci data = *(buf+offs); 4948c2ecf20Sopenharmony_ci offs++; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (data == DLE) { 4978c2ecf20Sopenharmony_ci if (skip) { /* start of a new pkt */ 4988c2ecf20Sopenharmony_ci skip = 0; 4998c2ecf20Sopenharmony_ci size = GSP_INITIAL_OFFSET; 5008c2ecf20Sopenharmony_ci dleSeen = 1; 5018c2ecf20Sopenharmony_ci } else if (dleSeen) { 5028c2ecf20Sopenharmony_ci dest[size++] = data; 5038c2ecf20Sopenharmony_ci dleSeen = 0; 5048c2ecf20Sopenharmony_ci } else { 5058c2ecf20Sopenharmony_ci dleSeen = 1; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci } else if (data == ETX) { 5088c2ecf20Sopenharmony_ci if (dleSeen) { 5098c2ecf20Sopenharmony_ci /* packet complete */ 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci data = dest[GSP_INITIAL_OFFSET]; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (data == ACK) { 5148c2ecf20Sopenharmony_ci ack_or_nak_seen = ACK; 5158c2ecf20Sopenharmony_ci dev_dbg(dev, "ACK packet complete.\n"); 5168c2ecf20Sopenharmony_ci } else if (data == NAK) { 5178c2ecf20Sopenharmony_ci ack_or_nak_seen = NAK; 5188c2ecf20Sopenharmony_ci dev_dbg(dev, "NAK packet complete.\n"); 5198c2ecf20Sopenharmony_ci } else { 5208c2ecf20Sopenharmony_ci dev_dbg(dev, "packet complete - id=0x%X.\n", 5218c2ecf20Sopenharmony_ci data); 5228c2ecf20Sopenharmony_ci gsp_rec_packet(garmin_data_p, size); 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci skip = 1; 5268c2ecf20Sopenharmony_ci size = GSP_INITIAL_OFFSET; 5278c2ecf20Sopenharmony_ci dleSeen = 0; 5288c2ecf20Sopenharmony_ci } else { 5298c2ecf20Sopenharmony_ci dest[size++] = data; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci } else if (!skip) { 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (dleSeen) { 5348c2ecf20Sopenharmony_ci size = GSP_INITIAL_OFFSET; 5358c2ecf20Sopenharmony_ci dleSeen = 0; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci dest[size++] = data; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (size >= GPS_IN_BUFSIZ) { 5428c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - packet too large.\n", __func__); 5438c2ecf20Sopenharmony_ci skip = 1; 5448c2ecf20Sopenharmony_ci size = GSP_INITIAL_OFFSET; 5458c2ecf20Sopenharmony_ci dleSeen = 0; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci garmin_data_p->insize = size; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* copy flags back to structure */ 5548c2ecf20Sopenharmony_ci if (skip) 5558c2ecf20Sopenharmony_ci garmin_data_p->flags |= FLAGS_GSP_SKIP; 5568c2ecf20Sopenharmony_ci else 5578c2ecf20Sopenharmony_ci garmin_data_p->flags &= ~FLAGS_GSP_SKIP; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci if (dleSeen) 5608c2ecf20Sopenharmony_ci garmin_data_p->flags |= FLAGS_GSP_DLESEEN; 5618c2ecf20Sopenharmony_ci else 5628c2ecf20Sopenharmony_ci garmin_data_p->flags &= ~FLAGS_GSP_DLESEEN; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (ack_or_nak_seen) { 5678c2ecf20Sopenharmony_ci if (gsp_next_packet(garmin_data_p) > 0) 5688c2ecf20Sopenharmony_ci garmin_data_p->state = STATE_ACTIVE; 5698c2ecf20Sopenharmony_ci else 5708c2ecf20Sopenharmony_ci garmin_data_p->state = STATE_GSP_WAIT_DATA; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci return count; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci/* 5788c2ecf20Sopenharmony_ci * Sends a usb packet to the tty 5798c2ecf20Sopenharmony_ci * 5808c2ecf20Sopenharmony_ci * Assumes, that all packages and at an usb-packet boundary. 5818c2ecf20Sopenharmony_ci * 5828c2ecf20Sopenharmony_ci * return <0 on error, 0 if packet is incomplete or > 0 if packet was sent 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_cistatic int gsp_send(struct garmin_data *garmin_data_p, 5858c2ecf20Sopenharmony_ci const unsigned char *buf, int count) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci struct device *dev = &garmin_data_p->port->dev; 5888c2ecf20Sopenharmony_ci const unsigned char *src; 5898c2ecf20Sopenharmony_ci unsigned char *dst; 5908c2ecf20Sopenharmony_ci int pktid = 0; 5918c2ecf20Sopenharmony_ci int datalen = 0; 5928c2ecf20Sopenharmony_ci int cksum = 0; 5938c2ecf20Sopenharmony_ci int i = 0; 5948c2ecf20Sopenharmony_ci int k; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - state %d - %d bytes.\n", __func__, 5978c2ecf20Sopenharmony_ci garmin_data_p->state, count); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci k = garmin_data_p->outsize; 6008c2ecf20Sopenharmony_ci if ((k+count) > GPS_OUT_BUFSIZ) { 6018c2ecf20Sopenharmony_ci dev_dbg(dev, "packet too large\n"); 6028c2ecf20Sopenharmony_ci garmin_data_p->outsize = 0; 6038c2ecf20Sopenharmony_ci return -4; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci memcpy(garmin_data_p->outbuffer+k, buf, count); 6078c2ecf20Sopenharmony_ci k += count; 6088c2ecf20Sopenharmony_ci garmin_data_p->outsize = k; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (k >= GARMIN_PKTHDR_LENGTH) { 6118c2ecf20Sopenharmony_ci pktid = getPacketId(garmin_data_p->outbuffer); 6128c2ecf20Sopenharmony_ci datalen = getDataLength(garmin_data_p->outbuffer); 6138c2ecf20Sopenharmony_ci i = GARMIN_PKTHDR_LENGTH + datalen; 6148c2ecf20Sopenharmony_ci if (k < i) 6158c2ecf20Sopenharmony_ci return 0; 6168c2ecf20Sopenharmony_ci } else { 6178c2ecf20Sopenharmony_ci return 0; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - %d bytes in buffer, %d bytes in pkt.\n", __func__, k, i); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* garmin_data_p->outbuffer now contains a complete packet */ 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci usb_serial_debug_data(&garmin_data_p->port->dev, __func__, k, 6258c2ecf20Sopenharmony_ci garmin_data_p->outbuffer); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci garmin_data_p->outsize = 0; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (getLayerId(garmin_data_p->outbuffer) != GARMIN_LAYERID_APPL) { 6308c2ecf20Sopenharmony_ci dev_dbg(dev, "not an application packet (%d)\n", 6318c2ecf20Sopenharmony_ci getLayerId(garmin_data_p->outbuffer)); 6328c2ecf20Sopenharmony_ci return -1; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (pktid > 255) { 6368c2ecf20Sopenharmony_ci dev_dbg(dev, "packet-id %d too large\n", pktid); 6378c2ecf20Sopenharmony_ci return -2; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (datalen > 255) { 6418c2ecf20Sopenharmony_ci dev_dbg(dev, "packet-size %d too large\n", datalen); 6428c2ecf20Sopenharmony_ci return -3; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* the serial protocol should be able to handle this packet */ 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci k = 0; 6488c2ecf20Sopenharmony_ci src = garmin_data_p->outbuffer+GARMIN_PKTHDR_LENGTH; 6498c2ecf20Sopenharmony_ci for (i = 0; i < datalen; i++) { 6508c2ecf20Sopenharmony_ci if (*src++ == DLE) 6518c2ecf20Sopenharmony_ci k++; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci src = garmin_data_p->outbuffer+GARMIN_PKTHDR_LENGTH; 6558c2ecf20Sopenharmony_ci if (k > (GARMIN_PKTHDR_LENGTH-2)) { 6568c2ecf20Sopenharmony_ci /* can't add stuffing DLEs in place, move data to end 6578c2ecf20Sopenharmony_ci of buffer ... */ 6588c2ecf20Sopenharmony_ci dst = garmin_data_p->outbuffer+GPS_OUT_BUFSIZ-datalen; 6598c2ecf20Sopenharmony_ci memcpy(dst, src, datalen); 6608c2ecf20Sopenharmony_ci src = dst; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci dst = garmin_data_p->outbuffer; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci *dst++ = DLE; 6668c2ecf20Sopenharmony_ci *dst++ = pktid; 6678c2ecf20Sopenharmony_ci cksum += pktid; 6688c2ecf20Sopenharmony_ci *dst++ = datalen; 6698c2ecf20Sopenharmony_ci cksum += datalen; 6708c2ecf20Sopenharmony_ci if (datalen == DLE) 6718c2ecf20Sopenharmony_ci *dst++ = DLE; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci for (i = 0; i < datalen; i++) { 6748c2ecf20Sopenharmony_ci __u8 c = *src++; 6758c2ecf20Sopenharmony_ci *dst++ = c; 6768c2ecf20Sopenharmony_ci cksum += c; 6778c2ecf20Sopenharmony_ci if (c == DLE) 6788c2ecf20Sopenharmony_ci *dst++ = DLE; 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci cksum = -cksum & 0xFF; 6828c2ecf20Sopenharmony_ci *dst++ = cksum; 6838c2ecf20Sopenharmony_ci if (cksum == DLE) 6848c2ecf20Sopenharmony_ci *dst++ = DLE; 6858c2ecf20Sopenharmony_ci *dst++ = DLE; 6868c2ecf20Sopenharmony_ci *dst++ = ETX; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci i = dst-garmin_data_p->outbuffer; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci send_to_tty(garmin_data_p->port, garmin_data_p->outbuffer, i); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci garmin_data_p->pkt_id = pktid; 6938c2ecf20Sopenharmony_ci garmin_data_p->state = STATE_WAIT_TTY_ACK; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci return i; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci/* 7008c2ecf20Sopenharmony_ci * Process the next pending data packet - if there is one 7018c2ecf20Sopenharmony_ci */ 7028c2ecf20Sopenharmony_cistatic int gsp_next_packet(struct garmin_data *garmin_data_p) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci int result = 0; 7058c2ecf20Sopenharmony_ci struct garmin_packet *pkt = NULL; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci while ((pkt = pkt_pop(garmin_data_p)) != NULL) { 7088c2ecf20Sopenharmony_ci dev_dbg(&garmin_data_p->port->dev, "%s - next pkt: %d\n", __func__, pkt->seq); 7098c2ecf20Sopenharmony_ci result = gsp_send(garmin_data_p, pkt->data, pkt->size); 7108c2ecf20Sopenharmony_ci if (result > 0) { 7118c2ecf20Sopenharmony_ci kfree(pkt); 7128c2ecf20Sopenharmony_ci return result; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci kfree(pkt); 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci return result; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci/****************************************************************************** 7228c2ecf20Sopenharmony_ci * garmin native mode 7238c2ecf20Sopenharmony_ci ******************************************************************************/ 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci/* 7278c2ecf20Sopenharmony_ci * Called for data received from tty 7288c2ecf20Sopenharmony_ci * 7298c2ecf20Sopenharmony_ci * The input data is expected to be in garmin usb-packet format. 7308c2ecf20Sopenharmony_ci * 7318c2ecf20Sopenharmony_ci * buf contains the data read, it may span more than one packet 7328c2ecf20Sopenharmony_ci * or even incomplete packets 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_cistatic int nat_receive(struct garmin_data *garmin_data_p, 7358c2ecf20Sopenharmony_ci const unsigned char *buf, int count) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci unsigned long flags; 7388c2ecf20Sopenharmony_ci __u8 *dest; 7398c2ecf20Sopenharmony_ci int offs = 0; 7408c2ecf20Sopenharmony_ci int result = count; 7418c2ecf20Sopenharmony_ci int len; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci while (offs < count) { 7448c2ecf20Sopenharmony_ci /* if buffer contains header, copy rest of data */ 7458c2ecf20Sopenharmony_ci if (garmin_data_p->insize >= GARMIN_PKTHDR_LENGTH) 7468c2ecf20Sopenharmony_ci len = GARMIN_PKTHDR_LENGTH 7478c2ecf20Sopenharmony_ci +getDataLength(garmin_data_p->inbuffer); 7488c2ecf20Sopenharmony_ci else 7498c2ecf20Sopenharmony_ci len = GARMIN_PKTHDR_LENGTH; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (len >= GPS_IN_BUFSIZ) { 7528c2ecf20Sopenharmony_ci /* seems to be an invalid packet, ignore rest 7538c2ecf20Sopenharmony_ci of input */ 7548c2ecf20Sopenharmony_ci dev_dbg(&garmin_data_p->port->dev, 7558c2ecf20Sopenharmony_ci "%s - packet size too large: %d\n", 7568c2ecf20Sopenharmony_ci __func__, len); 7578c2ecf20Sopenharmony_ci garmin_data_p->insize = 0; 7588c2ecf20Sopenharmony_ci count = 0; 7598c2ecf20Sopenharmony_ci result = -EINVPKT; 7608c2ecf20Sopenharmony_ci } else { 7618c2ecf20Sopenharmony_ci len -= garmin_data_p->insize; 7628c2ecf20Sopenharmony_ci if (len > (count-offs)) 7638c2ecf20Sopenharmony_ci len = (count-offs); 7648c2ecf20Sopenharmony_ci if (len > 0) { 7658c2ecf20Sopenharmony_ci dest = garmin_data_p->inbuffer 7668c2ecf20Sopenharmony_ci + garmin_data_p->insize; 7678c2ecf20Sopenharmony_ci memcpy(dest, buf+offs, len); 7688c2ecf20Sopenharmony_ci garmin_data_p->insize += len; 7698c2ecf20Sopenharmony_ci offs += len; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci /* do we have a complete packet ? */ 7748c2ecf20Sopenharmony_ci if (garmin_data_p->insize >= GARMIN_PKTHDR_LENGTH) { 7758c2ecf20Sopenharmony_ci len = GARMIN_PKTHDR_LENGTH+ 7768c2ecf20Sopenharmony_ci getDataLength(garmin_data_p->inbuffer); 7778c2ecf20Sopenharmony_ci if (garmin_data_p->insize >= len) { 7788c2ecf20Sopenharmony_ci garmin_write_bulk(garmin_data_p->port, 7798c2ecf20Sopenharmony_ci garmin_data_p->inbuffer, 7808c2ecf20Sopenharmony_ci len, 0); 7818c2ecf20Sopenharmony_ci garmin_data_p->insize = 0; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci /* if this was an abort-transfer command, 7848c2ecf20Sopenharmony_ci flush all queued data. */ 7858c2ecf20Sopenharmony_ci if (isAbortTrfCmnd(garmin_data_p->inbuffer)) { 7868c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, 7878c2ecf20Sopenharmony_ci flags); 7888c2ecf20Sopenharmony_ci garmin_data_p->flags |= FLAGS_DROP_DATA; 7898c2ecf20Sopenharmony_ci spin_unlock_irqrestore( 7908c2ecf20Sopenharmony_ci &garmin_data_p->lock, flags); 7918c2ecf20Sopenharmony_ci pkt_clear(garmin_data_p); 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci return result; 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci/****************************************************************************** 8018c2ecf20Sopenharmony_ci * private packets 8028c2ecf20Sopenharmony_ci ******************************************************************************/ 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_cistatic void priv_status_resp(struct usb_serial_port *port) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 8078c2ecf20Sopenharmony_ci __le32 *pkt = (__le32 *)garmin_data_p->privpkt; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci pkt[0] = __cpu_to_le32(GARMIN_LAYERID_PRIVATE); 8108c2ecf20Sopenharmony_ci pkt[1] = __cpu_to_le32(PRIV_PKTID_INFO_RESP); 8118c2ecf20Sopenharmony_ci pkt[2] = __cpu_to_le32(12); 8128c2ecf20Sopenharmony_ci pkt[3] = __cpu_to_le32(VERSION_MAJOR << 16 | VERSION_MINOR); 8138c2ecf20Sopenharmony_ci pkt[4] = __cpu_to_le32(garmin_data_p->mode); 8148c2ecf20Sopenharmony_ci pkt[5] = __cpu_to_le32(garmin_data_p->serial_num); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci send_to_tty(port, (__u8 *)pkt, 6 * 4); 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci/****************************************************************************** 8218c2ecf20Sopenharmony_ci * Garmin specific driver functions 8228c2ecf20Sopenharmony_ci ******************************************************************************/ 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic int process_resetdev_request(struct usb_serial_port *port) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci unsigned long flags; 8278c2ecf20Sopenharmony_ci int status; 8288c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 8318c2ecf20Sopenharmony_ci garmin_data_p->flags &= ~(CLEAR_HALT_REQUIRED); 8328c2ecf20Sopenharmony_ci garmin_data_p->state = STATE_RESET; 8338c2ecf20Sopenharmony_ci garmin_data_p->serial_num = 0; 8348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 8378c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - usb_reset_device\n", __func__); 8388c2ecf20Sopenharmony_ci status = usb_reset_device(port->serial->dev); 8398c2ecf20Sopenharmony_ci if (status) 8408c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - usb_reset_device failed: %d\n", 8418c2ecf20Sopenharmony_ci __func__, status); 8428c2ecf20Sopenharmony_ci return status; 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci/* 8488c2ecf20Sopenharmony_ci * clear all cached data 8498c2ecf20Sopenharmony_ci */ 8508c2ecf20Sopenharmony_cistatic int garmin_clear(struct garmin_data *garmin_data_p) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci unsigned long flags; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* flush all queued data */ 8558c2ecf20Sopenharmony_ci pkt_clear(garmin_data_p); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 8588c2ecf20Sopenharmony_ci garmin_data_p->insize = 0; 8598c2ecf20Sopenharmony_ci garmin_data_p->outsize = 0; 8608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci return 0; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_cistatic int garmin_init_session(struct usb_serial_port *port) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 8698c2ecf20Sopenharmony_ci int status; 8708c2ecf20Sopenharmony_ci int i; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 8758c2ecf20Sopenharmony_ci if (status) { 8768c2ecf20Sopenharmony_ci dev_err(&port->dev, "failed to submit interrupt urb: %d\n", 8778c2ecf20Sopenharmony_ci status); 8788c2ecf20Sopenharmony_ci return status; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci /* 8828c2ecf20Sopenharmony_ci * using the initialization method from gpsbabel. See comments in 8838c2ecf20Sopenharmony_ci * gpsbabel/jeeps/gpslibusb.c gusb_reset_toggles() 8848c2ecf20Sopenharmony_ci */ 8858c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - starting session ...\n", __func__); 8868c2ecf20Sopenharmony_ci garmin_data_p->state = STATE_ACTIVE; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 8898c2ecf20Sopenharmony_ci status = garmin_write_bulk(port, GARMIN_START_SESSION_REQ, 8908c2ecf20Sopenharmony_ci sizeof(GARMIN_START_SESSION_REQ), 0); 8918c2ecf20Sopenharmony_ci if (status < 0) 8928c2ecf20Sopenharmony_ci goto err_kill_urbs; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci return 0; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cierr_kill_urbs: 8988c2ecf20Sopenharmony_ci usb_kill_anchored_urbs(&garmin_data_p->write_urbs); 8998c2ecf20Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci return status; 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_cistatic int garmin_open(struct tty_struct *tty, struct usb_serial_port *port) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci unsigned long flags; 9098c2ecf20Sopenharmony_ci int status = 0; 9108c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 9138c2ecf20Sopenharmony_ci garmin_data_p->mode = initial_mode; 9148c2ecf20Sopenharmony_ci garmin_data_p->count = 0; 9158c2ecf20Sopenharmony_ci garmin_data_p->flags &= FLAGS_SESSION_REPLY1_SEEN; 9168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci /* shutdown any bulk reads that might be going on */ 9198c2ecf20Sopenharmony_ci usb_kill_urb(port->read_urb); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci if (garmin_data_p->state == STATE_RESET) 9228c2ecf20Sopenharmony_ci status = garmin_init_session(port); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci garmin_data_p->state = STATE_ACTIVE; 9258c2ecf20Sopenharmony_ci return status; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic void garmin_close(struct usb_serial_port *port) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - mode=%d state=%d flags=0x%X\n", 9348c2ecf20Sopenharmony_ci __func__, garmin_data_p->mode, garmin_data_p->state, 9358c2ecf20Sopenharmony_ci garmin_data_p->flags); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci garmin_clear(garmin_data_p); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci /* shutdown our urbs */ 9408c2ecf20Sopenharmony_ci usb_kill_urb(port->read_urb); 9418c2ecf20Sopenharmony_ci usb_kill_anchored_urbs(&garmin_data_p->write_urbs); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* keep reset state so we know that we must start a new session */ 9448c2ecf20Sopenharmony_ci if (garmin_data_p->state != STATE_RESET) 9458c2ecf20Sopenharmony_ci garmin_data_p->state = STATE_DISCONNECTED; 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_cistatic void garmin_write_bulk_callback(struct urb *urb) 9508c2ecf20Sopenharmony_ci{ 9518c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (port) { 9548c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = 9558c2ecf20Sopenharmony_ci usb_get_serial_port_data(port); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if (getLayerId(urb->transfer_buffer) == GARMIN_LAYERID_APPL) { 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { 9608c2ecf20Sopenharmony_ci gsp_send_ack(garmin_data_p, 9618c2ecf20Sopenharmony_ci ((__u8 *)urb->transfer_buffer)[4]); 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci usb_serial_port_softint(port); 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci /* Ignore errors that resulted from garmin_write_bulk with 9688c2ecf20Sopenharmony_ci dismiss_ack = 1 */ 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci /* free up the transfer buffer, as usb_free_urb() does not do this */ 9718c2ecf20Sopenharmony_ci kfree(urb->transfer_buffer); 9728c2ecf20Sopenharmony_ci} 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic int garmin_write_bulk(struct usb_serial_port *port, 9768c2ecf20Sopenharmony_ci const unsigned char *buf, int count, 9778c2ecf20Sopenharmony_ci int dismiss_ack) 9788c2ecf20Sopenharmony_ci{ 9798c2ecf20Sopenharmony_ci unsigned long flags; 9808c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 9818c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 9828c2ecf20Sopenharmony_ci struct urb *urb; 9838c2ecf20Sopenharmony_ci unsigned char *buffer; 9848c2ecf20Sopenharmony_ci int status; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 9878c2ecf20Sopenharmony_ci garmin_data_p->flags &= ~FLAGS_DROP_DATA; 9888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci buffer = kmalloc(count, GFP_ATOMIC); 9918c2ecf20Sopenharmony_ci if (!buffer) 9928c2ecf20Sopenharmony_ci return -ENOMEM; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci urb = usb_alloc_urb(0, GFP_ATOMIC); 9958c2ecf20Sopenharmony_ci if (!urb) { 9968c2ecf20Sopenharmony_ci kfree(buffer); 9978c2ecf20Sopenharmony_ci return -ENOMEM; 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci memcpy(buffer, buf, count); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci usb_serial_debug_data(&port->dev, __func__, count, buffer); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci usb_fill_bulk_urb(urb, serial->dev, 10058c2ecf20Sopenharmony_ci usb_sndbulkpipe(serial->dev, 10068c2ecf20Sopenharmony_ci port->bulk_out_endpointAddress), 10078c2ecf20Sopenharmony_ci buffer, count, 10088c2ecf20Sopenharmony_ci garmin_write_bulk_callback, 10098c2ecf20Sopenharmony_ci dismiss_ack ? NULL : port); 10108c2ecf20Sopenharmony_ci urb->transfer_flags |= URB_ZERO_PACKET; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci if (getLayerId(buffer) == GARMIN_LAYERID_APPL) { 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 10158c2ecf20Sopenharmony_ci garmin_data_p->flags |= APP_REQ_SEEN; 10168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { 10198c2ecf20Sopenharmony_ci pkt_clear(garmin_data_p); 10208c2ecf20Sopenharmony_ci garmin_data_p->state = STATE_GSP_WAIT_DATA; 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci /* send it down the pipe */ 10258c2ecf20Sopenharmony_ci usb_anchor_urb(urb, &garmin_data_p->write_urbs); 10268c2ecf20Sopenharmony_ci status = usb_submit_urb(urb, GFP_ATOMIC); 10278c2ecf20Sopenharmony_ci if (status) { 10288c2ecf20Sopenharmony_ci dev_err(&port->dev, 10298c2ecf20Sopenharmony_ci "%s - usb_submit_urb(write bulk) failed with status = %d\n", 10308c2ecf20Sopenharmony_ci __func__, status); 10318c2ecf20Sopenharmony_ci count = status; 10328c2ecf20Sopenharmony_ci usb_unanchor_urb(urb); 10338c2ecf20Sopenharmony_ci kfree(buffer); 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci /* we are done with this urb, so let the host driver 10378c2ecf20Sopenharmony_ci * really free it when it is finished with it */ 10388c2ecf20Sopenharmony_ci usb_free_urb(urb); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci return count; 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_cistatic int garmin_write(struct tty_struct *tty, struct usb_serial_port *port, 10448c2ecf20Sopenharmony_ci const unsigned char *buf, int count) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci struct device *dev = &port->dev; 10478c2ecf20Sopenharmony_ci int pktid, pktsiz, len; 10488c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 10498c2ecf20Sopenharmony_ci __le32 *privpkt = (__le32 *)garmin_data_p->privpkt; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci usb_serial_debug_data(dev, __func__, count, buf); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci if (garmin_data_p->state == STATE_RESET) 10548c2ecf20Sopenharmony_ci return -EIO; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci /* check for our private packets */ 10578c2ecf20Sopenharmony_ci if (count >= GARMIN_PKTHDR_LENGTH) { 10588c2ecf20Sopenharmony_ci len = PRIVPKTSIZ; 10598c2ecf20Sopenharmony_ci if (count < len) 10608c2ecf20Sopenharmony_ci len = count; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci memcpy(garmin_data_p->privpkt, buf, len); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci pktsiz = getDataLength(garmin_data_p->privpkt); 10658c2ecf20Sopenharmony_ci pktid = getPacketId(garmin_data_p->privpkt); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (count == (GARMIN_PKTHDR_LENGTH + pktsiz) && 10688c2ecf20Sopenharmony_ci getLayerId(garmin_data_p->privpkt) == 10698c2ecf20Sopenharmony_ci GARMIN_LAYERID_PRIVATE) { 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - processing private request %d\n", 10728c2ecf20Sopenharmony_ci __func__, pktid); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci /* drop all unfinished transfers */ 10758c2ecf20Sopenharmony_ci garmin_clear(garmin_data_p); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci switch (pktid) { 10788c2ecf20Sopenharmony_ci case PRIV_PKTID_SET_MODE: 10798c2ecf20Sopenharmony_ci if (pktsiz != 4) 10808c2ecf20Sopenharmony_ci return -EINVPKT; 10818c2ecf20Sopenharmony_ci garmin_data_p->mode = __le32_to_cpu(privpkt[3]); 10828c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - mode set to %d\n", 10838c2ecf20Sopenharmony_ci __func__, garmin_data_p->mode); 10848c2ecf20Sopenharmony_ci break; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci case PRIV_PKTID_INFO_REQ: 10878c2ecf20Sopenharmony_ci priv_status_resp(port); 10888c2ecf20Sopenharmony_ci break; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci case PRIV_PKTID_RESET_REQ: 10918c2ecf20Sopenharmony_ci process_resetdev_request(port); 10928c2ecf20Sopenharmony_ci break; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci case PRIV_PKTID_SET_DEF_MODE: 10958c2ecf20Sopenharmony_ci if (pktsiz != 4) 10968c2ecf20Sopenharmony_ci return -EINVPKT; 10978c2ecf20Sopenharmony_ci initial_mode = __le32_to_cpu(privpkt[3]); 10988c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - initial_mode set to %d\n", 10998c2ecf20Sopenharmony_ci __func__, 11008c2ecf20Sopenharmony_ci garmin_data_p->mode); 11018c2ecf20Sopenharmony_ci break; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci return count; 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { 11088c2ecf20Sopenharmony_ci return gsp_receive(garmin_data_p, buf, count); 11098c2ecf20Sopenharmony_ci } else { /* MODE_NATIVE */ 11108c2ecf20Sopenharmony_ci return nat_receive(garmin_data_p, buf, count); 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci} 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cistatic int garmin_write_room(struct tty_struct *tty) 11168c2ecf20Sopenharmony_ci{ 11178c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 11188c2ecf20Sopenharmony_ci /* 11198c2ecf20Sopenharmony_ci * Report back the bytes currently available in the output buffer. 11208c2ecf20Sopenharmony_ci */ 11218c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 11228c2ecf20Sopenharmony_ci return GPS_OUT_BUFSIZ-garmin_data_p->outsize; 11238c2ecf20Sopenharmony_ci} 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistatic void garmin_read_process(struct garmin_data *garmin_data_p, 11278c2ecf20Sopenharmony_ci unsigned char *data, unsigned data_length, 11288c2ecf20Sopenharmony_ci int bulk_data) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci unsigned long flags; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci if (garmin_data_p->flags & FLAGS_DROP_DATA) { 11338c2ecf20Sopenharmony_ci /* abort-transfer cmd is active */ 11348c2ecf20Sopenharmony_ci dev_dbg(&garmin_data_p->port->dev, "%s - pkt dropped\n", __func__); 11358c2ecf20Sopenharmony_ci } else if (garmin_data_p->state != STATE_DISCONNECTED && 11368c2ecf20Sopenharmony_ci garmin_data_p->state != STATE_RESET) { 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci /* if throttling is active or postprecessing is required 11398c2ecf20Sopenharmony_ci put the received data in the input queue, otherwise 11408c2ecf20Sopenharmony_ci send it directly to the tty port */ 11418c2ecf20Sopenharmony_ci if (garmin_data_p->flags & FLAGS_QUEUING) { 11428c2ecf20Sopenharmony_ci pkt_add(garmin_data_p, data, data_length); 11438c2ecf20Sopenharmony_ci } else if (bulk_data || (data_length >= sizeof(u32) && 11448c2ecf20Sopenharmony_ci getLayerId(data) == GARMIN_LAYERID_APPL)) { 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 11478c2ecf20Sopenharmony_ci garmin_data_p->flags |= APP_RESP_SEEN; 11488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { 11518c2ecf20Sopenharmony_ci pkt_add(garmin_data_p, data, data_length); 11528c2ecf20Sopenharmony_ci } else { 11538c2ecf20Sopenharmony_ci send_to_tty(garmin_data_p->port, data, 11548c2ecf20Sopenharmony_ci data_length); 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci /* ignore system layer packets ... */ 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci} 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_cistatic void garmin_read_bulk_callback(struct urb *urb) 11638c2ecf20Sopenharmony_ci{ 11648c2ecf20Sopenharmony_ci unsigned long flags; 11658c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 11668c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 11678c2ecf20Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 11688c2ecf20Sopenharmony_ci int status = urb->status; 11698c2ecf20Sopenharmony_ci int retval; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci if (status) { 11728c2ecf20Sopenharmony_ci dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n", 11738c2ecf20Sopenharmony_ci __func__, status); 11748c2ecf20Sopenharmony_ci return; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci garmin_read_process(garmin_data_p, data, urb->actual_length, 1); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci if (urb->actual_length == 0 && 11828c2ecf20Sopenharmony_ci (garmin_data_p->flags & FLAGS_BULK_IN_RESTART) != 0) { 11838c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 11848c2ecf20Sopenharmony_ci garmin_data_p->flags &= ~FLAGS_BULK_IN_RESTART; 11858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 11868c2ecf20Sopenharmony_ci retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); 11878c2ecf20Sopenharmony_ci if (retval) 11888c2ecf20Sopenharmony_ci dev_err(&port->dev, 11898c2ecf20Sopenharmony_ci "%s - failed resubmitting read urb, error %d\n", 11908c2ecf20Sopenharmony_ci __func__, retval); 11918c2ecf20Sopenharmony_ci } else if (urb->actual_length > 0) { 11928c2ecf20Sopenharmony_ci /* Continue trying to read until nothing more is received */ 11938c2ecf20Sopenharmony_ci if ((garmin_data_p->flags & FLAGS_THROTTLED) == 0) { 11948c2ecf20Sopenharmony_ci retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); 11958c2ecf20Sopenharmony_ci if (retval) 11968c2ecf20Sopenharmony_ci dev_err(&port->dev, 11978c2ecf20Sopenharmony_ci "%s - failed resubmitting read urb, error %d\n", 11988c2ecf20Sopenharmony_ci __func__, retval); 11998c2ecf20Sopenharmony_ci } 12008c2ecf20Sopenharmony_ci } else { 12018c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - end of bulk data\n", __func__); 12028c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 12038c2ecf20Sopenharmony_ci garmin_data_p->flags &= ~FLAGS_BULK_IN_ACTIVE; 12048c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci} 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_cistatic void garmin_read_int_callback(struct urb *urb) 12108c2ecf20Sopenharmony_ci{ 12118c2ecf20Sopenharmony_ci unsigned long flags; 12128c2ecf20Sopenharmony_ci int retval; 12138c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 12148c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 12158c2ecf20Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 12168c2ecf20Sopenharmony_ci int status = urb->status; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci switch (status) { 12198c2ecf20Sopenharmony_ci case 0: 12208c2ecf20Sopenharmony_ci /* success */ 12218c2ecf20Sopenharmony_ci break; 12228c2ecf20Sopenharmony_ci case -ECONNRESET: 12238c2ecf20Sopenharmony_ci case -ENOENT: 12248c2ecf20Sopenharmony_ci case -ESHUTDOWN: 12258c2ecf20Sopenharmony_ci /* this urb is terminated, clean up */ 12268c2ecf20Sopenharmony_ci dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", 12278c2ecf20Sopenharmony_ci __func__, status); 12288c2ecf20Sopenharmony_ci return; 12298c2ecf20Sopenharmony_ci default: 12308c2ecf20Sopenharmony_ci dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", 12318c2ecf20Sopenharmony_ci __func__, status); 12328c2ecf20Sopenharmony_ci return; 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci usb_serial_debug_data(&port->dev, __func__, urb->actual_length, 12368c2ecf20Sopenharmony_ci urb->transfer_buffer); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci if (urb->actual_length == sizeof(GARMIN_BULK_IN_AVAIL_REPLY) && 12398c2ecf20Sopenharmony_ci memcmp(data, GARMIN_BULK_IN_AVAIL_REPLY, 12408c2ecf20Sopenharmony_ci sizeof(GARMIN_BULK_IN_AVAIL_REPLY)) == 0) { 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - bulk data available.\n", __func__); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci if ((garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE) == 0) { 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci /* bulk data available */ 12478c2ecf20Sopenharmony_ci retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); 12488c2ecf20Sopenharmony_ci if (retval) { 12498c2ecf20Sopenharmony_ci dev_err(&port->dev, 12508c2ecf20Sopenharmony_ci "%s - failed submitting read urb, error %d\n", 12518c2ecf20Sopenharmony_ci __func__, retval); 12528c2ecf20Sopenharmony_ci } else { 12538c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 12548c2ecf20Sopenharmony_ci garmin_data_p->flags |= FLAGS_BULK_IN_ACTIVE; 12558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, 12568c2ecf20Sopenharmony_ci flags); 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci } else { 12598c2ecf20Sopenharmony_ci /* bulk-in transfer still active */ 12608c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 12618c2ecf20Sopenharmony_ci garmin_data_p->flags |= FLAGS_BULK_IN_RESTART; 12628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci } else if (urb->actual_length == (4+sizeof(GARMIN_START_SESSION_REPLY)) 12668c2ecf20Sopenharmony_ci && memcmp(data, GARMIN_START_SESSION_REPLY, 12678c2ecf20Sopenharmony_ci sizeof(GARMIN_START_SESSION_REPLY)) == 0) { 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 12708c2ecf20Sopenharmony_ci garmin_data_p->flags |= FLAGS_SESSION_REPLY1_SEEN; 12718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci /* save the serial number */ 12748c2ecf20Sopenharmony_ci garmin_data_p->serial_num = __le32_to_cpup( 12758c2ecf20Sopenharmony_ci (__le32 *)(data+GARMIN_PKTHDR_LENGTH)); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - start-of-session reply seen - serial %u.\n", 12788c2ecf20Sopenharmony_ci __func__, garmin_data_p->serial_num); 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci garmin_read_process(garmin_data_p, data, urb->actual_length, 0); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci retval = usb_submit_urb(urb, GFP_ATOMIC); 12848c2ecf20Sopenharmony_ci if (retval) 12858c2ecf20Sopenharmony_ci dev_err(&urb->dev->dev, 12868c2ecf20Sopenharmony_ci "%s - Error %d submitting interrupt urb\n", 12878c2ecf20Sopenharmony_ci __func__, retval); 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci/* 12928c2ecf20Sopenharmony_ci * Sends the next queued packt to the tty port (garmin native mode only) 12938c2ecf20Sopenharmony_ci * and then sets a timer to call itself again until all queued data 12948c2ecf20Sopenharmony_ci * is sent. 12958c2ecf20Sopenharmony_ci */ 12968c2ecf20Sopenharmony_cistatic int garmin_flush_queue(struct garmin_data *garmin_data_p) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci unsigned long flags; 12998c2ecf20Sopenharmony_ci struct garmin_packet *pkt; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci if ((garmin_data_p->flags & FLAGS_THROTTLED) == 0) { 13028c2ecf20Sopenharmony_ci pkt = pkt_pop(garmin_data_p); 13038c2ecf20Sopenharmony_ci if (pkt != NULL) { 13048c2ecf20Sopenharmony_ci send_to_tty(garmin_data_p->port, pkt->data, pkt->size); 13058c2ecf20Sopenharmony_ci kfree(pkt); 13068c2ecf20Sopenharmony_ci mod_timer(&garmin_data_p->timer, (1)+jiffies); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci } else { 13098c2ecf20Sopenharmony_ci spin_lock_irqsave(&garmin_data_p->lock, flags); 13108c2ecf20Sopenharmony_ci garmin_data_p->flags &= ~FLAGS_QUEUING; 13118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&garmin_data_p->lock, flags); 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci return 0; 13158c2ecf20Sopenharmony_ci} 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_cistatic void garmin_throttle(struct tty_struct *tty) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 13218c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* set flag, data received will be put into a queue 13248c2ecf20Sopenharmony_ci for later processing */ 13258c2ecf20Sopenharmony_ci spin_lock_irq(&garmin_data_p->lock); 13268c2ecf20Sopenharmony_ci garmin_data_p->flags |= FLAGS_QUEUING|FLAGS_THROTTLED; 13278c2ecf20Sopenharmony_ci spin_unlock_irq(&garmin_data_p->lock); 13288c2ecf20Sopenharmony_ci} 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic void garmin_unthrottle(struct tty_struct *tty) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 13348c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 13358c2ecf20Sopenharmony_ci int status; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci spin_lock_irq(&garmin_data_p->lock); 13388c2ecf20Sopenharmony_ci garmin_data_p->flags &= ~FLAGS_THROTTLED; 13398c2ecf20Sopenharmony_ci spin_unlock_irq(&garmin_data_p->lock); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci /* in native mode send queued data to tty, in 13428c2ecf20Sopenharmony_ci serial mode nothing needs to be done here */ 13438c2ecf20Sopenharmony_ci if (garmin_data_p->mode == MODE_NATIVE) 13448c2ecf20Sopenharmony_ci garmin_flush_queue(garmin_data_p); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci if ((garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE) != 0) { 13478c2ecf20Sopenharmony_ci status = usb_submit_urb(port->read_urb, GFP_KERNEL); 13488c2ecf20Sopenharmony_ci if (status) 13498c2ecf20Sopenharmony_ci dev_err(&port->dev, 13508c2ecf20Sopenharmony_ci "%s - failed resubmitting read urb, error %d\n", 13518c2ecf20Sopenharmony_ci __func__, status); 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci} 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci/* 13568c2ecf20Sopenharmony_ci * The timer is currently only used to send queued packets to 13578c2ecf20Sopenharmony_ci * the tty in cases where the protocol provides no own handshaking 13588c2ecf20Sopenharmony_ci * to initiate the transfer. 13598c2ecf20Sopenharmony_ci */ 13608c2ecf20Sopenharmony_cistatic void timeout_handler(struct timer_list *t) 13618c2ecf20Sopenharmony_ci{ 13628c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = from_timer(garmin_data_p, t, timer); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci /* send the next queued packet to the tty port */ 13658c2ecf20Sopenharmony_ci if (garmin_data_p->mode == MODE_NATIVE) 13668c2ecf20Sopenharmony_ci if (garmin_data_p->flags & FLAGS_QUEUING) 13678c2ecf20Sopenharmony_ci garmin_flush_queue(garmin_data_p); 13688c2ecf20Sopenharmony_ci} 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_cistatic int garmin_port_probe(struct usb_serial_port *port) 13738c2ecf20Sopenharmony_ci{ 13748c2ecf20Sopenharmony_ci int status; 13758c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL); 13788c2ecf20Sopenharmony_ci if (!garmin_data_p) 13798c2ecf20Sopenharmony_ci return -ENOMEM; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci timer_setup(&garmin_data_p->timer, timeout_handler, 0); 13828c2ecf20Sopenharmony_ci spin_lock_init(&garmin_data_p->lock); 13838c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&garmin_data_p->pktlist); 13848c2ecf20Sopenharmony_ci garmin_data_p->port = port; 13858c2ecf20Sopenharmony_ci garmin_data_p->state = 0; 13868c2ecf20Sopenharmony_ci garmin_data_p->flags = 0; 13878c2ecf20Sopenharmony_ci garmin_data_p->count = 0; 13888c2ecf20Sopenharmony_ci init_usb_anchor(&garmin_data_p->write_urbs); 13898c2ecf20Sopenharmony_ci usb_set_serial_port_data(port, garmin_data_p); 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci status = garmin_init_session(port); 13928c2ecf20Sopenharmony_ci if (status) 13938c2ecf20Sopenharmony_ci goto err_free; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci return 0; 13968c2ecf20Sopenharmony_cierr_free: 13978c2ecf20Sopenharmony_ci kfree(garmin_data_p); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci return status; 14008c2ecf20Sopenharmony_ci} 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_cistatic int garmin_port_remove(struct usb_serial_port *port) 14048c2ecf20Sopenharmony_ci{ 14058c2ecf20Sopenharmony_ci struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci usb_kill_anchored_urbs(&garmin_data_p->write_urbs); 14088c2ecf20Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 14098c2ecf20Sopenharmony_ci del_timer_sync(&garmin_data_p->timer); 14108c2ecf20Sopenharmony_ci kfree(garmin_data_p); 14118c2ecf20Sopenharmony_ci return 0; 14128c2ecf20Sopenharmony_ci} 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci/* All of the device info needed */ 14168c2ecf20Sopenharmony_cistatic struct usb_serial_driver garmin_device = { 14178c2ecf20Sopenharmony_ci .driver = { 14188c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 14198c2ecf20Sopenharmony_ci .name = "garmin_gps", 14208c2ecf20Sopenharmony_ci }, 14218c2ecf20Sopenharmony_ci .description = "Garmin GPS usb/tty", 14228c2ecf20Sopenharmony_ci .id_table = id_table, 14238c2ecf20Sopenharmony_ci .num_ports = 1, 14248c2ecf20Sopenharmony_ci .open = garmin_open, 14258c2ecf20Sopenharmony_ci .close = garmin_close, 14268c2ecf20Sopenharmony_ci .throttle = garmin_throttle, 14278c2ecf20Sopenharmony_ci .unthrottle = garmin_unthrottle, 14288c2ecf20Sopenharmony_ci .port_probe = garmin_port_probe, 14298c2ecf20Sopenharmony_ci .port_remove = garmin_port_remove, 14308c2ecf20Sopenharmony_ci .write = garmin_write, 14318c2ecf20Sopenharmony_ci .write_room = garmin_write_room, 14328c2ecf20Sopenharmony_ci .write_bulk_callback = garmin_write_bulk_callback, 14338c2ecf20Sopenharmony_ci .read_bulk_callback = garmin_read_bulk_callback, 14348c2ecf20Sopenharmony_ci .read_int_callback = garmin_read_int_callback, 14358c2ecf20Sopenharmony_ci}; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 14388c2ecf20Sopenharmony_ci &garmin_device, NULL 14398c2ecf20Sopenharmony_ci}; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 14448c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 14458c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_cimodule_param(initial_mode, int, S_IRUGO); 14488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(initial_mode, "Initial mode"); 1449