18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * IEEE-1284 implementation for parport. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Authors: Phil Blundell <philb@gnu.org> 58c2ecf20Sopenharmony_ci * Carsten Gross <carsten@sol.wohnheim.uni-ulm.de> 68c2ecf20Sopenharmony_ci * Jose Renau <renau@acm.org> 78c2ecf20Sopenharmony_ci * Tim Waugh <tim@cyberelk.demon.co.uk> (largely rewritten) 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This file is responsible for IEEE 1284 negotiation, and for handing 108c2ecf20Sopenharmony_ci * read/write requests to low-level drivers. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Any part of this program may be used in documents licensed under 138c2ecf20Sopenharmony_ci * the GNU Free Documentation License, Version 1.1 or any later version 148c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Various hacks, Fred Barnes <frmb2@ukc.ac.uk>, 04/2000 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/threads.h> 218c2ecf20Sopenharmony_ci#include <linux/parport.h> 228c2ecf20Sopenharmony_ci#include <linux/delay.h> 238c2ecf20Sopenharmony_ci#include <linux/kernel.h> 248c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 258c2ecf20Sopenharmony_ci#include <linux/timer.h> 268c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#undef DEBUG /* undef me for production */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#ifdef CONFIG_LP_CONSOLE 318c2ecf20Sopenharmony_ci#undef DEBUG /* Don't want a garbled console */ 328c2ecf20Sopenharmony_ci#endif 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* Make parport_wait_peripheral wake up. 358c2ecf20Sopenharmony_ci * It will be useful to call this from an interrupt handler. */ 368c2ecf20Sopenharmony_cistatic void parport_ieee1284_wakeup (struct parport *port) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci up (&port->physport->ieee1284.irq); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void timeout_waiting_on_port (struct timer_list *t) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct parport *port = from_timer(port, t, timer); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci parport_ieee1284_wakeup (port); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/** 498c2ecf20Sopenharmony_ci * parport_wait_event - wait for an event on a parallel port 508c2ecf20Sopenharmony_ci * @port: port to wait on 518c2ecf20Sopenharmony_ci * @timeout: time to wait (in jiffies) 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * This function waits for up to @timeout jiffies for an 548c2ecf20Sopenharmony_ci * interrupt to occur on a parallel port. If the port timeout is 558c2ecf20Sopenharmony_ci * set to zero, it returns immediately. 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * If an interrupt occurs before the timeout period elapses, this 588c2ecf20Sopenharmony_ci * function returns zero immediately. If it times out, it returns 598c2ecf20Sopenharmony_ci * one. An error code less than zero indicates an error (most 608c2ecf20Sopenharmony_ci * likely a pending signal), and the calling code should finish 618c2ecf20Sopenharmony_ci * what it's doing as soon as it can. 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ciint parport_wait_event (struct parport *port, signed long timeout) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci int ret; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (!port->physport->cad->timeout) 698c2ecf20Sopenharmony_ci /* Zero timeout is special, and we can't down() the 708c2ecf20Sopenharmony_ci semaphore. */ 718c2ecf20Sopenharmony_ci return 1; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci timer_setup(&port->timer, timeout_waiting_on_port, 0); 748c2ecf20Sopenharmony_ci mod_timer(&port->timer, jiffies + timeout); 758c2ecf20Sopenharmony_ci ret = down_interruptible (&port->physport->ieee1284.irq); 768c2ecf20Sopenharmony_ci if (!del_timer_sync(&port->timer) && !ret) 778c2ecf20Sopenharmony_ci /* Timed out. */ 788c2ecf20Sopenharmony_ci ret = 1; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return ret; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/** 848c2ecf20Sopenharmony_ci * parport_poll_peripheral - poll status lines 858c2ecf20Sopenharmony_ci * @port: port to watch 868c2ecf20Sopenharmony_ci * @mask: status lines to watch 878c2ecf20Sopenharmony_ci * @result: desired values of chosen status lines 888c2ecf20Sopenharmony_ci * @usec: timeout 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * This function busy-waits until the masked status lines have 918c2ecf20Sopenharmony_ci * the desired values, or until the timeout period elapses. The 928c2ecf20Sopenharmony_ci * @mask and @result parameters are bitmasks, with the bits 938c2ecf20Sopenharmony_ci * defined by the constants in parport.h: %PARPORT_STATUS_BUSY, 948c2ecf20Sopenharmony_ci * and so on. 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * This function does not call schedule(); instead it busy-waits 978c2ecf20Sopenharmony_ci * using udelay(). It currently has a resolution of 5usec. 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * If the status lines take on the desired values before the 1008c2ecf20Sopenharmony_ci * timeout period elapses, parport_poll_peripheral() returns zero 1018c2ecf20Sopenharmony_ci * immediately. A return value greater than zero indicates 1028c2ecf20Sopenharmony_ci * a timeout. An error code (less than zero) indicates an error, 1038c2ecf20Sopenharmony_ci * most likely a signal that arrived, and the caller should 1048c2ecf20Sopenharmony_ci * finish what it is doing as soon as possible. 1058c2ecf20Sopenharmony_ci*/ 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ciint parport_poll_peripheral(struct parport *port, 1088c2ecf20Sopenharmony_ci unsigned char mask, 1098c2ecf20Sopenharmony_ci unsigned char result, 1108c2ecf20Sopenharmony_ci int usec) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci /* Zero return code is success, >0 is timeout. */ 1138c2ecf20Sopenharmony_ci int count = usec / 5 + 2; 1148c2ecf20Sopenharmony_ci int i; 1158c2ecf20Sopenharmony_ci unsigned char status; 1168c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 1178c2ecf20Sopenharmony_ci status = parport_read_status (port); 1188c2ecf20Sopenharmony_ci if ((status & mask) == result) 1198c2ecf20Sopenharmony_ci return 0; 1208c2ecf20Sopenharmony_ci if (signal_pending (current)) 1218c2ecf20Sopenharmony_ci return -EINTR; 1228c2ecf20Sopenharmony_ci if (need_resched()) 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci if (i >= 2) 1258c2ecf20Sopenharmony_ci udelay (5); 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci return 1; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/** 1328c2ecf20Sopenharmony_ci * parport_wait_peripheral - wait for status lines to change in 35ms 1338c2ecf20Sopenharmony_ci * @port: port to watch 1348c2ecf20Sopenharmony_ci * @mask: status lines to watch 1358c2ecf20Sopenharmony_ci * @result: desired values of chosen status lines 1368c2ecf20Sopenharmony_ci * 1378c2ecf20Sopenharmony_ci * This function waits until the masked status lines have the 1388c2ecf20Sopenharmony_ci * desired values, or until 35ms have elapsed (see IEEE 1284-1994 1398c2ecf20Sopenharmony_ci * page 24 to 25 for why this value in particular is hardcoded). 1408c2ecf20Sopenharmony_ci * The @mask and @result parameters are bitmasks, with the bits 1418c2ecf20Sopenharmony_ci * defined by the constants in parport.h: %PARPORT_STATUS_BUSY, 1428c2ecf20Sopenharmony_ci * and so on. 1438c2ecf20Sopenharmony_ci * 1448c2ecf20Sopenharmony_ci * The port is polled quickly to start off with, in anticipation 1458c2ecf20Sopenharmony_ci * of a fast response from the peripheral. This fast polling 1468c2ecf20Sopenharmony_ci * time is configurable (using /proc), and defaults to 500usec. 1478c2ecf20Sopenharmony_ci * If the timeout for this port (see parport_set_timeout()) is 1488c2ecf20Sopenharmony_ci * zero, the fast polling time is 35ms, and this function does 1498c2ecf20Sopenharmony_ci * not call schedule(). 1508c2ecf20Sopenharmony_ci * 1518c2ecf20Sopenharmony_ci * If the timeout for this port is non-zero, after the fast 1528c2ecf20Sopenharmony_ci * polling fails it uses parport_wait_event() to wait for up to 1538c2ecf20Sopenharmony_ci * 10ms, waking up if an interrupt occurs. 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ciint parport_wait_peripheral(struct parport *port, 1578c2ecf20Sopenharmony_ci unsigned char mask, 1588c2ecf20Sopenharmony_ci unsigned char result) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci int ret; 1618c2ecf20Sopenharmony_ci int usec; 1628c2ecf20Sopenharmony_ci unsigned long deadline; 1638c2ecf20Sopenharmony_ci unsigned char status; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci usec = port->physport->spintime; /* usecs of fast polling */ 1668c2ecf20Sopenharmony_ci if (!port->physport->cad->timeout) 1678c2ecf20Sopenharmony_ci /* A zero timeout is "special": busy wait for the 1688c2ecf20Sopenharmony_ci entire 35ms. */ 1698c2ecf20Sopenharmony_ci usec = 35000; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* Fast polling. 1728c2ecf20Sopenharmony_ci * 1738c2ecf20Sopenharmony_ci * This should be adjustable. 1748c2ecf20Sopenharmony_ci * How about making a note (in the device structure) of how long 1758c2ecf20Sopenharmony_ci * it takes, so we know for next time? 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_ci ret = parport_poll_peripheral (port, mask, result, usec); 1788c2ecf20Sopenharmony_ci if (ret != 1) 1798c2ecf20Sopenharmony_ci return ret; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (!port->physport->cad->timeout) 1828c2ecf20Sopenharmony_ci /* We may be in an interrupt handler, so we can't poll 1838c2ecf20Sopenharmony_ci * slowly anyway. */ 1848c2ecf20Sopenharmony_ci return 1; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* 40ms of slow polling. */ 1878c2ecf20Sopenharmony_ci deadline = jiffies + msecs_to_jiffies(40); 1888c2ecf20Sopenharmony_ci while (time_before (jiffies, deadline)) { 1898c2ecf20Sopenharmony_ci if (signal_pending (current)) 1908c2ecf20Sopenharmony_ci return -EINTR; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* Wait for 10ms (or until an interrupt occurs if 1938c2ecf20Sopenharmony_ci * the handler is set) */ 1948c2ecf20Sopenharmony_ci if ((ret = parport_wait_event (port, msecs_to_jiffies(10))) < 0) 1958c2ecf20Sopenharmony_ci return ret; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci status = parport_read_status (port); 1988c2ecf20Sopenharmony_ci if ((status & mask) == result) 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (!ret) { 2028c2ecf20Sopenharmony_ci /* parport_wait_event didn't time out, but the 2038c2ecf20Sopenharmony_ci * peripheral wasn't actually ready either. 2048c2ecf20Sopenharmony_ci * Wait for another 10ms. */ 2058c2ecf20Sopenharmony_ci schedule_timeout_interruptible(msecs_to_jiffies(10)); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return 1; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_1284 2138c2ecf20Sopenharmony_ci/* Terminate a negotiated mode. */ 2148c2ecf20Sopenharmony_cistatic void parport_ieee1284_terminate (struct parport *port) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci int r; 2178c2ecf20Sopenharmony_ci port = port->physport; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* EPP terminates differently. */ 2208c2ecf20Sopenharmony_ci switch (port->ieee1284.mode) { 2218c2ecf20Sopenharmony_ci case IEEE1284_MODE_EPP: 2228c2ecf20Sopenharmony_ci case IEEE1284_MODE_EPPSL: 2238c2ecf20Sopenharmony_ci case IEEE1284_MODE_EPPSWE: 2248c2ecf20Sopenharmony_ci /* Terminate from EPP mode. */ 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* Event 68: Set nInit low */ 2278c2ecf20Sopenharmony_ci parport_frob_control (port, PARPORT_CONTROL_INIT, 0); 2288c2ecf20Sopenharmony_ci udelay (50); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* Event 69: Set nInit high, nSelectIn low */ 2318c2ecf20Sopenharmony_ci parport_frob_control (port, 2328c2ecf20Sopenharmony_ci PARPORT_CONTROL_SELECT 2338c2ecf20Sopenharmony_ci | PARPORT_CONTROL_INIT, 2348c2ecf20Sopenharmony_ci PARPORT_CONTROL_SELECT 2358c2ecf20Sopenharmony_ci | PARPORT_CONTROL_INIT); 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci case IEEE1284_MODE_ECP: 2398c2ecf20Sopenharmony_ci case IEEE1284_MODE_ECPRLE: 2408c2ecf20Sopenharmony_ci case IEEE1284_MODE_ECPSWE: 2418c2ecf20Sopenharmony_ci /* In ECP we can only terminate from fwd idle phase. */ 2428c2ecf20Sopenharmony_ci if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE) { 2438c2ecf20Sopenharmony_ci /* Event 47: Set nInit high */ 2448c2ecf20Sopenharmony_ci parport_frob_control (port, 2458c2ecf20Sopenharmony_ci PARPORT_CONTROL_INIT 2468c2ecf20Sopenharmony_ci | PARPORT_CONTROL_AUTOFD, 2478c2ecf20Sopenharmony_ci PARPORT_CONTROL_INIT 2488c2ecf20Sopenharmony_ci | PARPORT_CONTROL_AUTOFD); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* Event 49: PError goes high */ 2518c2ecf20Sopenharmony_ci r = parport_wait_peripheral (port, 2528c2ecf20Sopenharmony_ci PARPORT_STATUS_PAPEROUT, 2538c2ecf20Sopenharmony_ci PARPORT_STATUS_PAPEROUT); 2548c2ecf20Sopenharmony_ci if (r) 2558c2ecf20Sopenharmony_ci pr_debug("%s: Timeout at event 49\n", 2568c2ecf20Sopenharmony_ci port->name); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci parport_data_forward (port); 2598c2ecf20Sopenharmony_ci pr_debug("%s: ECP direction: forward\n", port->name); 2608c2ecf20Sopenharmony_ci port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci fallthrough; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci default: 2668c2ecf20Sopenharmony_ci /* Terminate from all other modes. */ 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* Event 22: Set nSelectIn low, nAutoFd high */ 2698c2ecf20Sopenharmony_ci parport_frob_control (port, 2708c2ecf20Sopenharmony_ci PARPORT_CONTROL_SELECT 2718c2ecf20Sopenharmony_ci | PARPORT_CONTROL_AUTOFD, 2728c2ecf20Sopenharmony_ci PARPORT_CONTROL_SELECT); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* Event 24: nAck goes low */ 2758c2ecf20Sopenharmony_ci r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0); 2768c2ecf20Sopenharmony_ci if (r) 2778c2ecf20Sopenharmony_ci pr_debug("%s: Timeout at event 24\n", port->name); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* Event 25: Set nAutoFd low */ 2808c2ecf20Sopenharmony_ci parport_frob_control (port, 2818c2ecf20Sopenharmony_ci PARPORT_CONTROL_AUTOFD, 2828c2ecf20Sopenharmony_ci PARPORT_CONTROL_AUTOFD); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Event 27: nAck goes high */ 2858c2ecf20Sopenharmony_ci r = parport_wait_peripheral (port, 2868c2ecf20Sopenharmony_ci PARPORT_STATUS_ACK, 2878c2ecf20Sopenharmony_ci PARPORT_STATUS_ACK); 2888c2ecf20Sopenharmony_ci if (r) 2898c2ecf20Sopenharmony_ci pr_debug("%s: Timeout at event 27\n", port->name); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* Event 29: Set nAutoFd high */ 2928c2ecf20Sopenharmony_ci parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci port->ieee1284.mode = IEEE1284_MODE_COMPAT; 2968c2ecf20Sopenharmony_ci port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci pr_debug("%s: In compatibility (forward idle) mode\n", port->name); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci#endif /* IEEE1284 support */ 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci/** 3038c2ecf20Sopenharmony_ci * parport_negotiate - negotiate an IEEE 1284 mode 3048c2ecf20Sopenharmony_ci * @port: port to use 3058c2ecf20Sopenharmony_ci * @mode: mode to negotiate to 3068c2ecf20Sopenharmony_ci * 3078c2ecf20Sopenharmony_ci * Use this to negotiate to a particular IEEE 1284 transfer mode. 3088c2ecf20Sopenharmony_ci * The @mode parameter should be one of the constants in 3098c2ecf20Sopenharmony_ci * parport.h starting %IEEE1284_MODE_xxx. 3108c2ecf20Sopenharmony_ci * 3118c2ecf20Sopenharmony_ci * The return value is 0 if the peripheral has accepted the 3128c2ecf20Sopenharmony_ci * negotiation to the mode specified, -1 if the peripheral is not 3138c2ecf20Sopenharmony_ci * IEEE 1284 compliant (or not present), or 1 if the peripheral 3148c2ecf20Sopenharmony_ci * has rejected the negotiation. 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ciint parport_negotiate (struct parport *port, int mode) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci#ifndef CONFIG_PARPORT_1284 3208c2ecf20Sopenharmony_ci if (mode == IEEE1284_MODE_COMPAT) 3218c2ecf20Sopenharmony_ci return 0; 3228c2ecf20Sopenharmony_ci pr_err("parport: IEEE1284 not supported in this kernel\n"); 3238c2ecf20Sopenharmony_ci return -1; 3248c2ecf20Sopenharmony_ci#else 3258c2ecf20Sopenharmony_ci int m = mode & ~IEEE1284_ADDR; 3268c2ecf20Sopenharmony_ci int r; 3278c2ecf20Sopenharmony_ci unsigned char xflag; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci port = port->physport; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* Is there anything to do? */ 3328c2ecf20Sopenharmony_ci if (port->ieee1284.mode == mode) 3338c2ecf20Sopenharmony_ci return 0; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Is the difference just an address-or-not bit? */ 3368c2ecf20Sopenharmony_ci if ((port->ieee1284.mode & ~IEEE1284_ADDR) == (mode & ~IEEE1284_ADDR)){ 3378c2ecf20Sopenharmony_ci port->ieee1284.mode = mode; 3388c2ecf20Sopenharmony_ci return 0; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* Go to compatibility forward idle mode */ 3428c2ecf20Sopenharmony_ci if (port->ieee1284.mode != IEEE1284_MODE_COMPAT) 3438c2ecf20Sopenharmony_ci parport_ieee1284_terminate (port); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (mode == IEEE1284_MODE_COMPAT) 3468c2ecf20Sopenharmony_ci /* Compatibility mode: no negotiation. */ 3478c2ecf20Sopenharmony_ci return 0; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci switch (mode) { 3508c2ecf20Sopenharmony_ci case IEEE1284_MODE_ECPSWE: 3518c2ecf20Sopenharmony_ci m = IEEE1284_MODE_ECP; 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci case IEEE1284_MODE_EPPSL: 3548c2ecf20Sopenharmony_ci case IEEE1284_MODE_EPPSWE: 3558c2ecf20Sopenharmony_ci m = IEEE1284_MODE_EPP; 3568c2ecf20Sopenharmony_ci break; 3578c2ecf20Sopenharmony_ci case IEEE1284_MODE_BECP: 3588c2ecf20Sopenharmony_ci return -ENOSYS; /* FIXME (implement BECP) */ 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (mode & IEEE1284_EXT_LINK) 3628c2ecf20Sopenharmony_ci m = 1<<7; /* request extensibility link */ 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci port->ieee1284.phase = IEEE1284_PH_NEGOTIATION; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* Start off with nStrobe and nAutoFd high, and nSelectIn low */ 3678c2ecf20Sopenharmony_ci parport_frob_control (port, 3688c2ecf20Sopenharmony_ci PARPORT_CONTROL_STROBE 3698c2ecf20Sopenharmony_ci | PARPORT_CONTROL_AUTOFD 3708c2ecf20Sopenharmony_ci | PARPORT_CONTROL_SELECT, 3718c2ecf20Sopenharmony_ci PARPORT_CONTROL_SELECT); 3728c2ecf20Sopenharmony_ci udelay(1); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* Event 0: Set data */ 3758c2ecf20Sopenharmony_ci parport_data_forward (port); 3768c2ecf20Sopenharmony_ci parport_write_data (port, m); 3778c2ecf20Sopenharmony_ci udelay (400); /* Shouldn't need to wait this long. */ 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* Event 1: Set nSelectIn high, nAutoFd low */ 3808c2ecf20Sopenharmony_ci parport_frob_control (port, 3818c2ecf20Sopenharmony_ci PARPORT_CONTROL_SELECT 3828c2ecf20Sopenharmony_ci | PARPORT_CONTROL_AUTOFD, 3838c2ecf20Sopenharmony_ci PARPORT_CONTROL_AUTOFD); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* Event 2: PError, Select, nFault go high, nAck goes low */ 3868c2ecf20Sopenharmony_ci if (parport_wait_peripheral (port, 3878c2ecf20Sopenharmony_ci PARPORT_STATUS_ERROR 3888c2ecf20Sopenharmony_ci | PARPORT_STATUS_SELECT 3898c2ecf20Sopenharmony_ci | PARPORT_STATUS_PAPEROUT 3908c2ecf20Sopenharmony_ci | PARPORT_STATUS_ACK, 3918c2ecf20Sopenharmony_ci PARPORT_STATUS_ERROR 3928c2ecf20Sopenharmony_ci | PARPORT_STATUS_SELECT 3938c2ecf20Sopenharmony_ci | PARPORT_STATUS_PAPEROUT)) { 3948c2ecf20Sopenharmony_ci /* Timeout */ 3958c2ecf20Sopenharmony_ci parport_frob_control (port, 3968c2ecf20Sopenharmony_ci PARPORT_CONTROL_SELECT 3978c2ecf20Sopenharmony_ci | PARPORT_CONTROL_AUTOFD, 3988c2ecf20Sopenharmony_ci PARPORT_CONTROL_SELECT); 3998c2ecf20Sopenharmony_ci pr_debug("%s: Peripheral not IEEE1284 compliant (0x%02X)\n", 4008c2ecf20Sopenharmony_ci port->name, parport_read_status (port)); 4018c2ecf20Sopenharmony_ci port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; 4028c2ecf20Sopenharmony_ci return -1; /* Not IEEE1284 compliant */ 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci /* Event 3: Set nStrobe low */ 4068c2ecf20Sopenharmony_ci parport_frob_control (port, 4078c2ecf20Sopenharmony_ci PARPORT_CONTROL_STROBE, 4088c2ecf20Sopenharmony_ci PARPORT_CONTROL_STROBE); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci /* Event 4: Set nStrobe and nAutoFd high */ 4118c2ecf20Sopenharmony_ci udelay (5); 4128c2ecf20Sopenharmony_ci parport_frob_control (port, 4138c2ecf20Sopenharmony_ci PARPORT_CONTROL_STROBE 4148c2ecf20Sopenharmony_ci | PARPORT_CONTROL_AUTOFD, 4158c2ecf20Sopenharmony_ci 0); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* Event 6: nAck goes high */ 4188c2ecf20Sopenharmony_ci if (parport_wait_peripheral (port, 4198c2ecf20Sopenharmony_ci PARPORT_STATUS_ACK, 4208c2ecf20Sopenharmony_ci PARPORT_STATUS_ACK)) { 4218c2ecf20Sopenharmony_ci /* This shouldn't really happen with a compliant device. */ 4228c2ecf20Sopenharmony_ci pr_debug("%s: Mode 0x%02x not supported? (0x%02x)\n", 4238c2ecf20Sopenharmony_ci port->name, mode, port->ops->read_status (port)); 4248c2ecf20Sopenharmony_ci parport_ieee1284_terminate (port); 4258c2ecf20Sopenharmony_ci return 1; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci xflag = parport_read_status (port) & PARPORT_STATUS_SELECT; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci /* xflag should be high for all modes other than nibble (0). */ 4318c2ecf20Sopenharmony_ci if (mode && !xflag) { 4328c2ecf20Sopenharmony_ci /* Mode not supported. */ 4338c2ecf20Sopenharmony_ci pr_debug("%s: Mode 0x%02x rejected by peripheral\n", 4348c2ecf20Sopenharmony_ci port->name, mode); 4358c2ecf20Sopenharmony_ci parport_ieee1284_terminate (port); 4368c2ecf20Sopenharmony_ci return 1; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* More to do if we've requested extensibility link. */ 4408c2ecf20Sopenharmony_ci if (mode & IEEE1284_EXT_LINK) { 4418c2ecf20Sopenharmony_ci m = mode & 0x7f; 4428c2ecf20Sopenharmony_ci udelay (1); 4438c2ecf20Sopenharmony_ci parport_write_data (port, m); 4448c2ecf20Sopenharmony_ci udelay (1); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci /* Event 51: Set nStrobe low */ 4478c2ecf20Sopenharmony_ci parport_frob_control (port, 4488c2ecf20Sopenharmony_ci PARPORT_CONTROL_STROBE, 4498c2ecf20Sopenharmony_ci PARPORT_CONTROL_STROBE); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* Event 52: nAck goes low */ 4528c2ecf20Sopenharmony_ci if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) { 4538c2ecf20Sopenharmony_ci /* This peripheral is _very_ slow. */ 4548c2ecf20Sopenharmony_ci pr_debug("%s: Event 52 didn't happen\n", port->name); 4558c2ecf20Sopenharmony_ci parport_ieee1284_terminate (port); 4568c2ecf20Sopenharmony_ci return 1; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* Event 53: Set nStrobe high */ 4608c2ecf20Sopenharmony_ci parport_frob_control (port, 4618c2ecf20Sopenharmony_ci PARPORT_CONTROL_STROBE, 4628c2ecf20Sopenharmony_ci 0); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* Event 55: nAck goes high */ 4658c2ecf20Sopenharmony_ci if (parport_wait_peripheral (port, 4668c2ecf20Sopenharmony_ci PARPORT_STATUS_ACK, 4678c2ecf20Sopenharmony_ci PARPORT_STATUS_ACK)) { 4688c2ecf20Sopenharmony_ci /* This shouldn't really happen with a compliant 4698c2ecf20Sopenharmony_ci * device. */ 4708c2ecf20Sopenharmony_ci pr_debug("%s: Mode 0x%02x not supported? (0x%02x)\n", 4718c2ecf20Sopenharmony_ci port->name, mode, 4728c2ecf20Sopenharmony_ci port->ops->read_status(port)); 4738c2ecf20Sopenharmony_ci parport_ieee1284_terminate (port); 4748c2ecf20Sopenharmony_ci return 1; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* Event 54: Peripheral sets XFlag to reflect support */ 4788c2ecf20Sopenharmony_ci xflag = parport_read_status (port) & PARPORT_STATUS_SELECT; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* xflag should be high. */ 4818c2ecf20Sopenharmony_ci if (!xflag) { 4828c2ecf20Sopenharmony_ci /* Extended mode not supported. */ 4838c2ecf20Sopenharmony_ci pr_debug("%s: Extended mode 0x%02x not supported\n", 4848c2ecf20Sopenharmony_ci port->name, mode); 4858c2ecf20Sopenharmony_ci parport_ieee1284_terminate (port); 4868c2ecf20Sopenharmony_ci return 1; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* Any further setup is left to the caller. */ 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* Mode is supported */ 4938c2ecf20Sopenharmony_ci pr_debug("%s: In mode 0x%02x\n", port->name, mode); 4948c2ecf20Sopenharmony_ci port->ieee1284.mode = mode; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* But ECP is special */ 4978c2ecf20Sopenharmony_ci if (!(mode & IEEE1284_EXT_LINK) && (m & IEEE1284_MODE_ECP)) { 4988c2ecf20Sopenharmony_ci port->ieee1284.phase = IEEE1284_PH_ECP_SETUP; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* Event 30: Set nAutoFd low */ 5018c2ecf20Sopenharmony_ci parport_frob_control (port, 5028c2ecf20Sopenharmony_ci PARPORT_CONTROL_AUTOFD, 5038c2ecf20Sopenharmony_ci PARPORT_CONTROL_AUTOFD); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* Event 31: PError goes high. */ 5068c2ecf20Sopenharmony_ci r = parport_wait_peripheral (port, 5078c2ecf20Sopenharmony_ci PARPORT_STATUS_PAPEROUT, 5088c2ecf20Sopenharmony_ci PARPORT_STATUS_PAPEROUT); 5098c2ecf20Sopenharmony_ci if (r) { 5108c2ecf20Sopenharmony_ci pr_debug("%s: Timeout at event 31\n", port->name); 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; 5148c2ecf20Sopenharmony_ci pr_debug("%s: ECP direction: forward\n", port->name); 5158c2ecf20Sopenharmony_ci } else switch (mode) { 5168c2ecf20Sopenharmony_ci case IEEE1284_MODE_NIBBLE: 5178c2ecf20Sopenharmony_ci case IEEE1284_MODE_BYTE: 5188c2ecf20Sopenharmony_ci port->ieee1284.phase = IEEE1284_PH_REV_IDLE; 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci default: 5218c2ecf20Sopenharmony_ci port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci return 0; 5268c2ecf20Sopenharmony_ci#endif /* IEEE1284 support */ 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci/* Acknowledge that the peripheral has data available. 5308c2ecf20Sopenharmony_ci * Events 18-20, in order to get from Reverse Idle phase 5318c2ecf20Sopenharmony_ci * to Host Busy Data Available. 5328c2ecf20Sopenharmony_ci * This will most likely be called from an interrupt. 5338c2ecf20Sopenharmony_ci * Returns zero if data was available. 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_1284 5368c2ecf20Sopenharmony_cistatic int parport_ieee1284_ack_data_avail (struct parport *port) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci if (parport_read_status (port) & PARPORT_STATUS_ERROR) 5398c2ecf20Sopenharmony_ci /* Event 18 didn't happen. */ 5408c2ecf20Sopenharmony_ci return -1; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* Event 20: nAutoFd goes high. */ 5438c2ecf20Sopenharmony_ci port->ops->frob_control (port, PARPORT_CONTROL_AUTOFD, 0); 5448c2ecf20Sopenharmony_ci port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL; 5458c2ecf20Sopenharmony_ci return 0; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci#endif /* IEEE1284 support */ 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci/* Handle an interrupt. */ 5508c2ecf20Sopenharmony_civoid parport_ieee1284_interrupt (void *handle) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci struct parport *port = handle; 5538c2ecf20Sopenharmony_ci parport_ieee1284_wakeup (port); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_1284 5568c2ecf20Sopenharmony_ci if (port->ieee1284.phase == IEEE1284_PH_REV_IDLE) { 5578c2ecf20Sopenharmony_ci /* An interrupt in this phase means that data 5588c2ecf20Sopenharmony_ci * is now available. */ 5598c2ecf20Sopenharmony_ci pr_debug("%s: Data available\n", port->name); 5608c2ecf20Sopenharmony_ci parport_ieee1284_ack_data_avail (port); 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci#endif /* IEEE1284 support */ 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci/** 5668c2ecf20Sopenharmony_ci * parport_write - write a block of data to a parallel port 5678c2ecf20Sopenharmony_ci * @port: port to write to 5688c2ecf20Sopenharmony_ci * @buffer: data buffer (in kernel space) 5698c2ecf20Sopenharmony_ci * @len: number of bytes of data to transfer 5708c2ecf20Sopenharmony_ci * 5718c2ecf20Sopenharmony_ci * This will write up to @len bytes of @buffer to the port 5728c2ecf20Sopenharmony_ci * specified, using the IEEE 1284 transfer mode most recently 5738c2ecf20Sopenharmony_ci * negotiated to (using parport_negotiate()), as long as that 5748c2ecf20Sopenharmony_ci * mode supports forward transfers (host to peripheral). 5758c2ecf20Sopenharmony_ci * 5768c2ecf20Sopenharmony_ci * It is the caller's responsibility to ensure that the first 5778c2ecf20Sopenharmony_ci * @len bytes of @buffer are valid. 5788c2ecf20Sopenharmony_ci * 5798c2ecf20Sopenharmony_ci * This function returns the number of bytes transferred (if zero 5808c2ecf20Sopenharmony_ci * or positive), or else an error code. 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cissize_t parport_write (struct parport *port, const void *buffer, size_t len) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci#ifndef CONFIG_PARPORT_1284 5868c2ecf20Sopenharmony_ci return port->ops->compat_write_data (port, buffer, len, 0); 5878c2ecf20Sopenharmony_ci#else 5888c2ecf20Sopenharmony_ci ssize_t retval; 5898c2ecf20Sopenharmony_ci int mode = port->ieee1284.mode; 5908c2ecf20Sopenharmony_ci int addr = mode & IEEE1284_ADDR; 5918c2ecf20Sopenharmony_ci size_t (*fn) (struct parport *, const void *, size_t, int); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* Ignore the device-ID-request bit and the address bit. */ 5948c2ecf20Sopenharmony_ci mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* Use the mode we're in. */ 5978c2ecf20Sopenharmony_ci switch (mode) { 5988c2ecf20Sopenharmony_ci case IEEE1284_MODE_NIBBLE: 5998c2ecf20Sopenharmony_ci case IEEE1284_MODE_BYTE: 6008c2ecf20Sopenharmony_ci parport_negotiate (port, IEEE1284_MODE_COMPAT); 6018c2ecf20Sopenharmony_ci fallthrough; 6028c2ecf20Sopenharmony_ci case IEEE1284_MODE_COMPAT: 6038c2ecf20Sopenharmony_ci pr_debug("%s: Using compatibility mode\n", port->name); 6048c2ecf20Sopenharmony_ci fn = port->ops->compat_write_data; 6058c2ecf20Sopenharmony_ci break; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci case IEEE1284_MODE_EPP: 6088c2ecf20Sopenharmony_ci pr_debug("%s: Using EPP mode\n", port->name); 6098c2ecf20Sopenharmony_ci if (addr) { 6108c2ecf20Sopenharmony_ci fn = port->ops->epp_write_addr; 6118c2ecf20Sopenharmony_ci } else { 6128c2ecf20Sopenharmony_ci fn = port->ops->epp_write_data; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci break; 6158c2ecf20Sopenharmony_ci case IEEE1284_MODE_EPPSWE: 6168c2ecf20Sopenharmony_ci pr_debug("%s: Using software-emulated EPP mode\n", port->name); 6178c2ecf20Sopenharmony_ci if (addr) { 6188c2ecf20Sopenharmony_ci fn = parport_ieee1284_epp_write_addr; 6198c2ecf20Sopenharmony_ci } else { 6208c2ecf20Sopenharmony_ci fn = parport_ieee1284_epp_write_data; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci break; 6238c2ecf20Sopenharmony_ci case IEEE1284_MODE_ECP: 6248c2ecf20Sopenharmony_ci case IEEE1284_MODE_ECPRLE: 6258c2ecf20Sopenharmony_ci pr_debug("%s: Using ECP mode\n", port->name); 6268c2ecf20Sopenharmony_ci if (addr) { 6278c2ecf20Sopenharmony_ci fn = port->ops->ecp_write_addr; 6288c2ecf20Sopenharmony_ci } else { 6298c2ecf20Sopenharmony_ci fn = port->ops->ecp_write_data; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci break; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci case IEEE1284_MODE_ECPSWE: 6348c2ecf20Sopenharmony_ci pr_debug("%s: Using software-emulated ECP mode\n", port->name); 6358c2ecf20Sopenharmony_ci /* The caller has specified that it must be emulated, 6368c2ecf20Sopenharmony_ci * even if we have ECP hardware! */ 6378c2ecf20Sopenharmony_ci if (addr) { 6388c2ecf20Sopenharmony_ci fn = parport_ieee1284_ecp_write_addr; 6398c2ecf20Sopenharmony_ci } else { 6408c2ecf20Sopenharmony_ci fn = parport_ieee1284_ecp_write_data; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci break; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci default: 6458c2ecf20Sopenharmony_ci pr_debug("%s: Unknown mode 0x%02x\n", 6468c2ecf20Sopenharmony_ci port->name, port->ieee1284.mode); 6478c2ecf20Sopenharmony_ci return -ENOSYS; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci retval = (*fn) (port, buffer, len, 0); 6518c2ecf20Sopenharmony_ci pr_debug("%s: wrote %zd/%zu bytes\n", port->name, retval, len); 6528c2ecf20Sopenharmony_ci return retval; 6538c2ecf20Sopenharmony_ci#endif /* IEEE1284 support */ 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci/** 6578c2ecf20Sopenharmony_ci * parport_read - read a block of data from a parallel port 6588c2ecf20Sopenharmony_ci * @port: port to read from 6598c2ecf20Sopenharmony_ci * @buffer: data buffer (in kernel space) 6608c2ecf20Sopenharmony_ci * @len: number of bytes of data to transfer 6618c2ecf20Sopenharmony_ci * 6628c2ecf20Sopenharmony_ci * This will read up to @len bytes of @buffer to the port 6638c2ecf20Sopenharmony_ci * specified, using the IEEE 1284 transfer mode most recently 6648c2ecf20Sopenharmony_ci * negotiated to (using parport_negotiate()), as long as that 6658c2ecf20Sopenharmony_ci * mode supports reverse transfers (peripheral to host). 6668c2ecf20Sopenharmony_ci * 6678c2ecf20Sopenharmony_ci * It is the caller's responsibility to ensure that the first 6688c2ecf20Sopenharmony_ci * @len bytes of @buffer are available to write to. 6698c2ecf20Sopenharmony_ci * 6708c2ecf20Sopenharmony_ci * This function returns the number of bytes transferred (if zero 6718c2ecf20Sopenharmony_ci * or positive), or else an error code. 6728c2ecf20Sopenharmony_ci */ 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cissize_t parport_read (struct parport *port, void *buffer, size_t len) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci#ifndef CONFIG_PARPORT_1284 6778c2ecf20Sopenharmony_ci pr_err("parport: IEEE1284 not supported in this kernel\n"); 6788c2ecf20Sopenharmony_ci return -ENODEV; 6798c2ecf20Sopenharmony_ci#else 6808c2ecf20Sopenharmony_ci int mode = port->physport->ieee1284.mode; 6818c2ecf20Sopenharmony_ci int addr = mode & IEEE1284_ADDR; 6828c2ecf20Sopenharmony_ci size_t (*fn) (struct parport *, void *, size_t, int); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* Ignore the device-ID-request bit and the address bit. */ 6858c2ecf20Sopenharmony_ci mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* Use the mode we're in. */ 6888c2ecf20Sopenharmony_ci switch (mode) { 6898c2ecf20Sopenharmony_ci case IEEE1284_MODE_COMPAT: 6908c2ecf20Sopenharmony_ci /* if we can tri-state use BYTE mode instead of NIBBLE mode, 6918c2ecf20Sopenharmony_ci * if that fails, revert to NIBBLE mode -- ought to store somewhere 6928c2ecf20Sopenharmony_ci * the device's ability to do BYTE mode reverse transfers, so we don't 6938c2ecf20Sopenharmony_ci * end up needlessly calling negotiate(BYTE) repeately.. (fb) 6948c2ecf20Sopenharmony_ci */ 6958c2ecf20Sopenharmony_ci if ((port->physport->modes & PARPORT_MODE_TRISTATE) && 6968c2ecf20Sopenharmony_ci !parport_negotiate (port, IEEE1284_MODE_BYTE)) { 6978c2ecf20Sopenharmony_ci /* got into BYTE mode OK */ 6988c2ecf20Sopenharmony_ci pr_debug("%s: Using byte mode\n", port->name); 6998c2ecf20Sopenharmony_ci fn = port->ops->byte_read_data; 7008c2ecf20Sopenharmony_ci break; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci if (parport_negotiate (port, IEEE1284_MODE_NIBBLE)) { 7038c2ecf20Sopenharmony_ci return -EIO; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci fallthrough; /* to NIBBLE */ 7068c2ecf20Sopenharmony_ci case IEEE1284_MODE_NIBBLE: 7078c2ecf20Sopenharmony_ci pr_debug("%s: Using nibble mode\n", port->name); 7088c2ecf20Sopenharmony_ci fn = port->ops->nibble_read_data; 7098c2ecf20Sopenharmony_ci break; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci case IEEE1284_MODE_BYTE: 7128c2ecf20Sopenharmony_ci pr_debug("%s: Using byte mode\n", port->name); 7138c2ecf20Sopenharmony_ci fn = port->ops->byte_read_data; 7148c2ecf20Sopenharmony_ci break; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci case IEEE1284_MODE_EPP: 7178c2ecf20Sopenharmony_ci pr_debug("%s: Using EPP mode\n", port->name); 7188c2ecf20Sopenharmony_ci if (addr) { 7198c2ecf20Sopenharmony_ci fn = port->ops->epp_read_addr; 7208c2ecf20Sopenharmony_ci } else { 7218c2ecf20Sopenharmony_ci fn = port->ops->epp_read_data; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci break; 7248c2ecf20Sopenharmony_ci case IEEE1284_MODE_EPPSWE: 7258c2ecf20Sopenharmony_ci pr_debug("%s: Using software-emulated EPP mode\n", port->name); 7268c2ecf20Sopenharmony_ci if (addr) { 7278c2ecf20Sopenharmony_ci fn = parport_ieee1284_epp_read_addr; 7288c2ecf20Sopenharmony_ci } else { 7298c2ecf20Sopenharmony_ci fn = parport_ieee1284_epp_read_data; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci break; 7328c2ecf20Sopenharmony_ci case IEEE1284_MODE_ECP: 7338c2ecf20Sopenharmony_ci case IEEE1284_MODE_ECPRLE: 7348c2ecf20Sopenharmony_ci pr_debug("%s: Using ECP mode\n", port->name); 7358c2ecf20Sopenharmony_ci fn = port->ops->ecp_read_data; 7368c2ecf20Sopenharmony_ci break; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci case IEEE1284_MODE_ECPSWE: 7398c2ecf20Sopenharmony_ci pr_debug("%s: Using software-emulated ECP mode\n", port->name); 7408c2ecf20Sopenharmony_ci fn = parport_ieee1284_ecp_read_data; 7418c2ecf20Sopenharmony_ci break; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci default: 7448c2ecf20Sopenharmony_ci pr_debug("%s: Unknown mode 0x%02x\n", 7458c2ecf20Sopenharmony_ci port->name, port->physport->ieee1284.mode); 7468c2ecf20Sopenharmony_ci return -ENOSYS; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci return (*fn) (port, buffer, len, 0); 7508c2ecf20Sopenharmony_ci#endif /* IEEE1284 support */ 7518c2ecf20Sopenharmony_ci} 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci/** 7548c2ecf20Sopenharmony_ci * parport_set_timeout - set the inactivity timeout for a device 7558c2ecf20Sopenharmony_ci * @dev: device on a port 7568c2ecf20Sopenharmony_ci * @inactivity: inactivity timeout (in jiffies) 7578c2ecf20Sopenharmony_ci * 7588c2ecf20Sopenharmony_ci * This sets the inactivity timeout for a particular device on a 7598c2ecf20Sopenharmony_ci * port. This affects functions like parport_wait_peripheral(). 7608c2ecf20Sopenharmony_ci * The special value 0 means not to call schedule() while dealing 7618c2ecf20Sopenharmony_ci * with this device. 7628c2ecf20Sopenharmony_ci * 7638c2ecf20Sopenharmony_ci * The return value is the previous inactivity timeout. 7648c2ecf20Sopenharmony_ci * 7658c2ecf20Sopenharmony_ci * Any callers of parport_wait_event() for this device are woken 7668c2ecf20Sopenharmony_ci * up. 7678c2ecf20Sopenharmony_ci */ 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cilong parport_set_timeout (struct pardevice *dev, long inactivity) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci long int old = dev->timeout; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci dev->timeout = inactivity; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (dev->port->physport->cad == dev) 7768c2ecf20Sopenharmony_ci parport_ieee1284_wakeup (dev->port); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci return old; 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci/* Exported symbols for modules. */ 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_negotiate); 7848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_write); 7858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_read); 7868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_wait_peripheral); 7878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_wait_event); 7888c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_set_timeout); 7898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_interrupt); 790