18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci paride.c (c) 1997-8 Grant R. Guenther <grant@torque.net> 38c2ecf20Sopenharmony_ci Under the terms of the GNU General Public License. 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci This is the base module for the family of device drivers 68c2ecf20Sopenharmony_ci that support parallel port IDE devices. 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci*/ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* Changes: 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci 1.01 GRG 1998.05.03 Use spinlocks 138c2ecf20Sopenharmony_ci 1.02 GRG 1998.05.05 init_proto, release_proto, ktti 148c2ecf20Sopenharmony_ci 1.03 GRG 1998.08.15 eliminate compiler warning 158c2ecf20Sopenharmony_ci 1.04 GRG 1998.11.28 added support for FRIQ 168c2ecf20Sopenharmony_ci 1.05 TMW 2000.06.06 use parport_find_number instead of 178c2ecf20Sopenharmony_ci parport_enumerate 188c2ecf20Sopenharmony_ci 1.06 TMW 2001.03.26 more sane parport-or-not resource management 198c2ecf20Sopenharmony_ci*/ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define PI_VERSION "1.06" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/module.h> 248c2ecf20Sopenharmony_ci#include <linux/kmod.h> 258c2ecf20Sopenharmony_ci#include <linux/types.h> 268c2ecf20Sopenharmony_ci#include <linux/kernel.h> 278c2ecf20Sopenharmony_ci#include <linux/ioport.h> 288c2ecf20Sopenharmony_ci#include <linux/string.h> 298c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 308c2ecf20Sopenharmony_ci#include <linux/wait.h> 318c2ecf20Sopenharmony_ci#include <linux/sched.h> /* TASK_* */ 328c2ecf20Sopenharmony_ci#include <linux/parport.h> 338c2ecf20Sopenharmony_ci#include <linux/slab.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "paride.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define MAX_PROTOS 32 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic struct pi_protocol *protocols[MAX_PROTOS]; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(pi_spinlock); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_civoid pi_write_regr(PIA * pi, int cont, int regr, int val) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci pi->proto->write_regr(pi, cont, regr, val); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_write_regr); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciint pi_read_regr(PIA * pi, int cont, int regr) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci return pi->proto->read_regr(pi, cont, regr); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_read_regr); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_civoid pi_write_block(PIA * pi, char *buf, int count) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci pi->proto->write_block(pi, buf, count); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_write_block); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_civoid pi_read_block(PIA * pi, char *buf, int count) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci pi->proto->read_block(pi, buf, count); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_read_block); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic void pi_wake_up(void *p) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci PIA *pi = (PIA *) p; 768c2ecf20Sopenharmony_ci unsigned long flags; 778c2ecf20Sopenharmony_ci void (*cont) (void) = NULL; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci spin_lock_irqsave(&pi_spinlock, flags); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (pi->claim_cont && !parport_claim(pi->pardev)) { 828c2ecf20Sopenharmony_ci cont = pi->claim_cont; 838c2ecf20Sopenharmony_ci pi->claim_cont = NULL; 848c2ecf20Sopenharmony_ci pi->claimed = 1; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pi_spinlock, flags); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci wake_up(&(pi->parq)); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (cont) 928c2ecf20Sopenharmony_ci cont(); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ciint pi_schedule_claimed(PIA * pi, void (*cont) (void)) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci unsigned long flags; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci spin_lock_irqsave(&pi_spinlock, flags); 1008c2ecf20Sopenharmony_ci if (pi->pardev && parport_claim(pi->pardev)) { 1018c2ecf20Sopenharmony_ci pi->claim_cont = cont; 1028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pi_spinlock, flags); 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci pi->claimed = 1; 1068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pi_spinlock, flags); 1078c2ecf20Sopenharmony_ci return 1; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_schedule_claimed); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_civoid pi_do_claimed(PIA * pi, void (*cont) (void)) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci if (pi_schedule_claimed(pi, cont)) 1148c2ecf20Sopenharmony_ci cont(); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_do_claimed); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic void pi_claim(PIA * pi) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci if (pi->claimed) 1228c2ecf20Sopenharmony_ci return; 1238c2ecf20Sopenharmony_ci pi->claimed = 1; 1248c2ecf20Sopenharmony_ci if (pi->pardev) 1258c2ecf20Sopenharmony_ci wait_event(pi->parq, 1268c2ecf20Sopenharmony_ci !parport_claim((struct pardevice *) pi->pardev)); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void pi_unclaim(PIA * pi) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci pi->claimed = 0; 1328c2ecf20Sopenharmony_ci if (pi->pardev) 1338c2ecf20Sopenharmony_ci parport_release((struct pardevice *) (pi->pardev)); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_civoid pi_connect(PIA * pi) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci pi_claim(pi); 1398c2ecf20Sopenharmony_ci pi->proto->connect(pi); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_connect); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_civoid pi_disconnect(PIA * pi) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci pi->proto->disconnect(pi); 1478c2ecf20Sopenharmony_ci pi_unclaim(pi); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_disconnect); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic void pi_unregister_parport(PIA * pi) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci if (pi->pardev) { 1558c2ecf20Sopenharmony_ci parport_unregister_device((struct pardevice *) (pi->pardev)); 1568c2ecf20Sopenharmony_ci pi->pardev = NULL; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_civoid pi_release(PIA * pi) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci pi_unregister_parport(pi); 1638c2ecf20Sopenharmony_ci if (pi->proto->release_proto) 1648c2ecf20Sopenharmony_ci pi->proto->release_proto(pi); 1658c2ecf20Sopenharmony_ci module_put(pi->proto->owner); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_release); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int default_test_proto(PIA * pi, char *scratch, int verbose) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci int j, k; 1738c2ecf20Sopenharmony_ci int e[2] = { 0, 0 }; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci pi->proto->connect(pi); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci for (j = 0; j < 2; j++) { 1788c2ecf20Sopenharmony_ci pi_write_regr(pi, 0, 6, 0xa0 + j * 0x10); 1798c2ecf20Sopenharmony_ci for (k = 0; k < 256; k++) { 1808c2ecf20Sopenharmony_ci pi_write_regr(pi, 0, 2, k ^ 0xaa); 1818c2ecf20Sopenharmony_ci pi_write_regr(pi, 0, 3, k ^ 0x55); 1828c2ecf20Sopenharmony_ci if (pi_read_regr(pi, 0, 2) != (k ^ 0xaa)) 1838c2ecf20Sopenharmony_ci e[j]++; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci pi->proto->disconnect(pi); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (verbose) 1898c2ecf20Sopenharmony_ci printk("%s: %s: port 0x%x, mode %d, test=(%d,%d)\n", 1908c2ecf20Sopenharmony_ci pi->device, pi->proto->name, pi->port, 1918c2ecf20Sopenharmony_ci pi->mode, e[0], e[1]); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return (e[0] && e[1]); /* not here if both > 0 */ 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic int pi_test_proto(PIA * pi, char *scratch, int verbose) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci int res; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci pi_claim(pi); 2018c2ecf20Sopenharmony_ci if (pi->proto->test_proto) 2028c2ecf20Sopenharmony_ci res = pi->proto->test_proto(pi, scratch, verbose); 2038c2ecf20Sopenharmony_ci else 2048c2ecf20Sopenharmony_ci res = default_test_proto(pi, scratch, verbose); 2058c2ecf20Sopenharmony_ci pi_unclaim(pi); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci return res; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ciint paride_register(PIP * pr) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci int k; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci for (k = 0; k < MAX_PROTOS; k++) 2158c2ecf20Sopenharmony_ci if (protocols[k] && !strcmp(pr->name, protocols[k]->name)) { 2168c2ecf20Sopenharmony_ci printk("paride: %s protocol already registered\n", 2178c2ecf20Sopenharmony_ci pr->name); 2188c2ecf20Sopenharmony_ci return -1; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci k = 0; 2218c2ecf20Sopenharmony_ci while ((k < MAX_PROTOS) && (protocols[k])) 2228c2ecf20Sopenharmony_ci k++; 2238c2ecf20Sopenharmony_ci if (k == MAX_PROTOS) { 2248c2ecf20Sopenharmony_ci printk("paride: protocol table full\n"); 2258c2ecf20Sopenharmony_ci return -1; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci protocols[k] = pr; 2288c2ecf20Sopenharmony_ci pr->index = k; 2298c2ecf20Sopenharmony_ci printk("paride: %s registered as protocol %d\n", pr->name, k); 2308c2ecf20Sopenharmony_ci return 0; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(paride_register); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_civoid paride_unregister(PIP * pr) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci if (!pr) 2388c2ecf20Sopenharmony_ci return; 2398c2ecf20Sopenharmony_ci if (protocols[pr->index] != pr) { 2408c2ecf20Sopenharmony_ci printk("paride: %s not registered\n", pr->name); 2418c2ecf20Sopenharmony_ci return; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci protocols[pr->index] = NULL; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(paride_unregister); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic int pi_register_parport(PIA *pi, int verbose, int unit) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci struct parport *port; 2518c2ecf20Sopenharmony_ci struct pardev_cb par_cb; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci port = parport_find_base(pi->port); 2548c2ecf20Sopenharmony_ci if (!port) 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci memset(&par_cb, 0, sizeof(par_cb)); 2578c2ecf20Sopenharmony_ci par_cb.wakeup = pi_wake_up; 2588c2ecf20Sopenharmony_ci par_cb.private = (void *)pi; 2598c2ecf20Sopenharmony_ci pi->pardev = parport_register_dev_model(port, pi->device, &par_cb, 2608c2ecf20Sopenharmony_ci unit); 2618c2ecf20Sopenharmony_ci parport_put_port(port); 2628c2ecf20Sopenharmony_ci if (!pi->pardev) 2638c2ecf20Sopenharmony_ci return 0; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci init_waitqueue_head(&pi->parq); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (verbose) 2688c2ecf20Sopenharmony_ci printk("%s: 0x%x is %s\n", pi->device, pi->port, port->name); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci pi->parname = (char *) port->name; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return 1; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic int pi_probe_mode(PIA * pi, int max, char *scratch, int verbose) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci int best, range; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (pi->mode != -1) { 2808c2ecf20Sopenharmony_ci if (pi->mode >= max) 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_ci range = 3; 2838c2ecf20Sopenharmony_ci if (pi->mode >= pi->proto->epp_first) 2848c2ecf20Sopenharmony_ci range = 8; 2858c2ecf20Sopenharmony_ci if ((range == 8) && (pi->port % 8)) 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci pi->reserved = range; 2888c2ecf20Sopenharmony_ci return (!pi_test_proto(pi, scratch, verbose)); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci best = -1; 2918c2ecf20Sopenharmony_ci for (pi->mode = 0; pi->mode < max; pi->mode++) { 2928c2ecf20Sopenharmony_ci range = 3; 2938c2ecf20Sopenharmony_ci if (pi->mode >= pi->proto->epp_first) 2948c2ecf20Sopenharmony_ci range = 8; 2958c2ecf20Sopenharmony_ci if ((range == 8) && (pi->port % 8)) 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci pi->reserved = range; 2988c2ecf20Sopenharmony_ci if (!pi_test_proto(pi, scratch, verbose)) 2998c2ecf20Sopenharmony_ci best = pi->mode; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci pi->mode = best; 3028c2ecf20Sopenharmony_ci return (best > -1); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int pi_probe_unit(PIA * pi, int unit, char *scratch, int verbose) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci int max, s, e; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci s = unit; 3108c2ecf20Sopenharmony_ci e = s + 1; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (s == -1) { 3138c2ecf20Sopenharmony_ci s = 0; 3148c2ecf20Sopenharmony_ci e = pi->proto->max_units; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (!pi_register_parport(pi, verbose, s)) 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (pi->proto->test_port) { 3218c2ecf20Sopenharmony_ci pi_claim(pi); 3228c2ecf20Sopenharmony_ci max = pi->proto->test_port(pi); 3238c2ecf20Sopenharmony_ci pi_unclaim(pi); 3248c2ecf20Sopenharmony_ci } else 3258c2ecf20Sopenharmony_ci max = pi->proto->max_mode; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (pi->proto->probe_unit) { 3288c2ecf20Sopenharmony_ci pi_claim(pi); 3298c2ecf20Sopenharmony_ci for (pi->unit = s; pi->unit < e; pi->unit++) 3308c2ecf20Sopenharmony_ci if (pi->proto->probe_unit(pi)) { 3318c2ecf20Sopenharmony_ci pi_unclaim(pi); 3328c2ecf20Sopenharmony_ci if (pi_probe_mode(pi, max, scratch, verbose)) 3338c2ecf20Sopenharmony_ci return 1; 3348c2ecf20Sopenharmony_ci pi_unregister_parport(pi); 3358c2ecf20Sopenharmony_ci return 0; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci pi_unclaim(pi); 3388c2ecf20Sopenharmony_ci pi_unregister_parport(pi); 3398c2ecf20Sopenharmony_ci return 0; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (!pi_probe_mode(pi, max, scratch, verbose)) { 3438c2ecf20Sopenharmony_ci pi_unregister_parport(pi); 3448c2ecf20Sopenharmony_ci return 0; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci return 1; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ciint pi_init(PIA * pi, int autoprobe, int port, int mode, 3518c2ecf20Sopenharmony_ci int unit, int protocol, int delay, char *scratch, 3528c2ecf20Sopenharmony_ci int devtype, int verbose, char *device) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci int p, k, s, e; 3558c2ecf20Sopenharmony_ci int lpts[7] = { 0x3bc, 0x378, 0x278, 0x268, 0x27c, 0x26c, 0 }; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci s = protocol; 3588c2ecf20Sopenharmony_ci e = s + 1; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (!protocols[0]) 3618c2ecf20Sopenharmony_ci request_module("paride_protocol"); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (autoprobe) { 3648c2ecf20Sopenharmony_ci s = 0; 3658c2ecf20Sopenharmony_ci e = MAX_PROTOS; 3668c2ecf20Sopenharmony_ci } else if ((s < 0) || (s >= MAX_PROTOS) || (port <= 0) || 3678c2ecf20Sopenharmony_ci (!protocols[s]) || (unit < 0) || 3688c2ecf20Sopenharmony_ci (unit >= protocols[s]->max_units)) { 3698c2ecf20Sopenharmony_ci printk("%s: Invalid parameters\n", device); 3708c2ecf20Sopenharmony_ci return 0; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci for (p = s; p < e; p++) { 3748c2ecf20Sopenharmony_ci struct pi_protocol *proto = protocols[p]; 3758c2ecf20Sopenharmony_ci if (!proto) 3768c2ecf20Sopenharmony_ci continue; 3778c2ecf20Sopenharmony_ci /* still racy */ 3788c2ecf20Sopenharmony_ci if (!try_module_get(proto->owner)) 3798c2ecf20Sopenharmony_ci continue; 3808c2ecf20Sopenharmony_ci pi->proto = proto; 3818c2ecf20Sopenharmony_ci pi->private = 0; 3828c2ecf20Sopenharmony_ci if (proto->init_proto && proto->init_proto(pi) < 0) { 3838c2ecf20Sopenharmony_ci pi->proto = NULL; 3848c2ecf20Sopenharmony_ci module_put(proto->owner); 3858c2ecf20Sopenharmony_ci continue; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci if (delay == -1) 3888c2ecf20Sopenharmony_ci pi->delay = pi->proto->default_delay; 3898c2ecf20Sopenharmony_ci else 3908c2ecf20Sopenharmony_ci pi->delay = delay; 3918c2ecf20Sopenharmony_ci pi->devtype = devtype; 3928c2ecf20Sopenharmony_ci pi->device = device; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci pi->parname = NULL; 3958c2ecf20Sopenharmony_ci pi->pardev = NULL; 3968c2ecf20Sopenharmony_ci init_waitqueue_head(&pi->parq); 3978c2ecf20Sopenharmony_ci pi->claimed = 0; 3988c2ecf20Sopenharmony_ci pi->claim_cont = NULL; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci pi->mode = mode; 4018c2ecf20Sopenharmony_ci if (port != -1) { 4028c2ecf20Sopenharmony_ci pi->port = port; 4038c2ecf20Sopenharmony_ci if (pi_probe_unit(pi, unit, scratch, verbose)) 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci pi->port = 0; 4068c2ecf20Sopenharmony_ci } else { 4078c2ecf20Sopenharmony_ci k = 0; 4088c2ecf20Sopenharmony_ci while ((pi->port = lpts[k++])) 4098c2ecf20Sopenharmony_ci if (pi_probe_unit 4108c2ecf20Sopenharmony_ci (pi, unit, scratch, verbose)) 4118c2ecf20Sopenharmony_ci break; 4128c2ecf20Sopenharmony_ci if (pi->port) 4138c2ecf20Sopenharmony_ci break; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci if (pi->proto->release_proto) 4168c2ecf20Sopenharmony_ci pi->proto->release_proto(pi); 4178c2ecf20Sopenharmony_ci module_put(proto->owner); 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (!pi->port) { 4218c2ecf20Sopenharmony_ci if (autoprobe) 4228c2ecf20Sopenharmony_ci printk("%s: Autoprobe failed\n", device); 4238c2ecf20Sopenharmony_ci else 4248c2ecf20Sopenharmony_ci printk("%s: Adapter not found\n", device); 4258c2ecf20Sopenharmony_ci return 0; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (pi->parname) 4298c2ecf20Sopenharmony_ci printk("%s: Sharing %s at 0x%x\n", pi->device, 4308c2ecf20Sopenharmony_ci pi->parname, pi->port); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci pi->proto->log_adapter(pi, scratch, verbose); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return 1; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_init); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int pi_probe(struct pardevice *par_dev) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct device_driver *drv = par_dev->dev.driver; 4428c2ecf20Sopenharmony_ci int len = strlen(drv->name); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (strncmp(par_dev->name, drv->name, len)) 4458c2ecf20Sopenharmony_ci return -ENODEV; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_civoid *pi_register_driver(char *name) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct parport_driver *parp_drv; 4538c2ecf20Sopenharmony_ci int ret; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci parp_drv = kzalloc(sizeof(*parp_drv), GFP_KERNEL); 4568c2ecf20Sopenharmony_ci if (!parp_drv) 4578c2ecf20Sopenharmony_ci return NULL; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci parp_drv->name = name; 4608c2ecf20Sopenharmony_ci parp_drv->probe = pi_probe; 4618c2ecf20Sopenharmony_ci parp_drv->devmodel = true; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci ret = parport_register_driver(parp_drv); 4648c2ecf20Sopenharmony_ci if (ret) { 4658c2ecf20Sopenharmony_ci kfree(parp_drv); 4668c2ecf20Sopenharmony_ci return NULL; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci return (void *)parp_drv; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_register_driver); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_civoid pi_unregister_driver(void *_drv) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci struct parport_driver *drv = _drv; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci parport_unregister_driver(drv); 4778c2ecf20Sopenharmony_ci kfree(drv); 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_unregister_driver); 480