18c2ecf20Sopenharmony_ci/*====================================================================== 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci A driver for PCMCIA parallel port adapters 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci (specifically, for the Quatech SPP-100 EPP card: other cards will 68c2ecf20Sopenharmony_ci probably require driver tweaks) 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci parport_cs.c 1.29 2002/10/11 06:57:41 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci The contents of this file are subject to the Mozilla Public 118c2ecf20Sopenharmony_ci License Version 1.1 (the "License"); you may not use this file 128c2ecf20Sopenharmony_ci except in compliance with the License. You may obtain a copy of 138c2ecf20Sopenharmony_ci the License at http://www.mozilla.org/MPL/ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci Software distributed under the License is distributed on an "AS 168c2ecf20Sopenharmony_ci IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 178c2ecf20Sopenharmony_ci implied. See the License for the specific language governing 188c2ecf20Sopenharmony_ci rights and limitations under the License. 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci The initial developer of the original code is David A. Hinds 218c2ecf20Sopenharmony_ci <dahinds@users.sourceforge.net>. Portions created by David A. Hinds 228c2ecf20Sopenharmony_ci are Copyright (C) 1999 David A. Hinds. All Rights Reserved. 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci Alternatively, the contents of this file may be used under the 258c2ecf20Sopenharmony_ci terms of the GNU General Public License version 2 (the "GPL"), in 268c2ecf20Sopenharmony_ci which case the provisions of the GPL are applicable instead of the 278c2ecf20Sopenharmony_ci above. If you wish to allow the use of your version of this file 288c2ecf20Sopenharmony_ci only under the terms of the GPL and not to allow others to use 298c2ecf20Sopenharmony_ci your version of this file under the MPL, indicate your decision 308c2ecf20Sopenharmony_ci by deleting the provisions above and replace them with the notice 318c2ecf20Sopenharmony_ci and other provisions required by the GPL. If you do not delete 328c2ecf20Sopenharmony_ci the provisions above, a recipient may use your version of this 338c2ecf20Sopenharmony_ci file under either the MPL or the GPL. 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci======================================================================*/ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <linux/kernel.h> 388c2ecf20Sopenharmony_ci#include <linux/module.h> 398c2ecf20Sopenharmony_ci#include <linux/init.h> 408c2ecf20Sopenharmony_ci#include <linux/ptrace.h> 418c2ecf20Sopenharmony_ci#include <linux/slab.h> 428c2ecf20Sopenharmony_ci#include <linux/string.h> 438c2ecf20Sopenharmony_ci#include <linux/timer.h> 448c2ecf20Sopenharmony_ci#include <linux/ioport.h> 458c2ecf20Sopenharmony_ci#include <linux/major.h> 468c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#include <linux/parport.h> 498c2ecf20Sopenharmony_ci#include <linux/parport_pc.h> 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#include <pcmcia/cistpl.h> 528c2ecf20Sopenharmony_ci#include <pcmcia/ds.h> 538c2ecf20Sopenharmony_ci#include <pcmcia/cisreg.h> 548c2ecf20Sopenharmony_ci#include <pcmcia/ciscode.h> 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/*====================================================================*/ 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* Module parameters */ 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ciMODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); 618c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PCMCIA parallel port card driver"); 628c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual MPL/GPL"); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ciINT_MODULE_PARM(epp_mode, 1); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/*====================================================================*/ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define FORCE_EPP_MODE 0x08 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_citypedef struct parport_info_t { 748c2ecf20Sopenharmony_ci struct pcmcia_device *p_dev; 758c2ecf20Sopenharmony_ci int ndev; 768c2ecf20Sopenharmony_ci struct parport *port; 778c2ecf20Sopenharmony_ci} parport_info_t; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic void parport_detach(struct pcmcia_device *p_dev); 808c2ecf20Sopenharmony_cistatic int parport_config(struct pcmcia_device *link); 818c2ecf20Sopenharmony_cistatic void parport_cs_release(struct pcmcia_device *); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int parport_probe(struct pcmcia_device *link) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci parport_info_t *info; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci dev_dbg(&link->dev, "parport_attach()\n"); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* Create new parport device */ 908c2ecf20Sopenharmony_ci info = kzalloc(sizeof(*info), GFP_KERNEL); 918c2ecf20Sopenharmony_ci if (!info) return -ENOMEM; 928c2ecf20Sopenharmony_ci link->priv = info; 938c2ecf20Sopenharmony_ci info->p_dev = link; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci return parport_config(link); 988c2ecf20Sopenharmony_ci} /* parport_attach */ 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic void parport_detach(struct pcmcia_device *link) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci dev_dbg(&link->dev, "parport_detach\n"); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci parport_cs_release(link); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci kfree(link->priv); 1078c2ecf20Sopenharmony_ci} /* parport_detach */ 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int parport_config_check(struct pcmcia_device *p_dev, void *priv_data) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; 1128c2ecf20Sopenharmony_ci p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; 1138c2ecf20Sopenharmony_ci p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; 1148c2ecf20Sopenharmony_ci p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return pcmcia_request_io(p_dev); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic int parport_config(struct pcmcia_device *link) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci parport_info_t *info = link->priv; 1228c2ecf20Sopenharmony_ci struct parport *p; 1238c2ecf20Sopenharmony_ci int ret; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci dev_dbg(&link->dev, "parport_config\n"); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (epp_mode) 1288c2ecf20Sopenharmony_ci link->config_index |= FORCE_EPP_MODE; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci ret = pcmcia_loop_config(link, parport_config_check, NULL); 1318c2ecf20Sopenharmony_ci if (ret) 1328c2ecf20Sopenharmony_ci goto failed; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (!link->irq) 1358c2ecf20Sopenharmony_ci goto failed; 1368c2ecf20Sopenharmony_ci ret = pcmcia_enable_device(link); 1378c2ecf20Sopenharmony_ci if (ret) 1388c2ecf20Sopenharmony_ci goto failed; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci p = parport_pc_probe_port(link->resource[0]->start, 1418c2ecf20Sopenharmony_ci link->resource[1]->start, 1428c2ecf20Sopenharmony_ci link->irq, PARPORT_DMA_NONE, 1438c2ecf20Sopenharmony_ci &link->dev, IRQF_SHARED); 1448c2ecf20Sopenharmony_ci if (p == NULL) { 1458c2ecf20Sopenharmony_ci pr_notice("parport_cs: parport_pc_probe_port() at 0x%3x, irq %u failed\n", 1468c2ecf20Sopenharmony_ci (unsigned int)link->resource[0]->start, link->irq); 1478c2ecf20Sopenharmony_ci goto failed; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci p->modes |= PARPORT_MODE_PCSPP; 1518c2ecf20Sopenharmony_ci if (epp_mode) 1528c2ecf20Sopenharmony_ci p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP; 1538c2ecf20Sopenharmony_ci info->ndev = 1; 1548c2ecf20Sopenharmony_ci info->port = p; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci return 0; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cifailed: 1598c2ecf20Sopenharmony_ci parport_cs_release(link); 1608c2ecf20Sopenharmony_ci kfree(link->priv); 1618c2ecf20Sopenharmony_ci return -ENODEV; 1628c2ecf20Sopenharmony_ci} /* parport_config */ 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic void parport_cs_release(struct pcmcia_device *link) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci parport_info_t *info = link->priv; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci dev_dbg(&link->dev, "parport_release\n"); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (info->ndev) { 1718c2ecf20Sopenharmony_ci struct parport *p = info->port; 1728c2ecf20Sopenharmony_ci parport_pc_unregister_port(p); 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci info->ndev = 0; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci pcmcia_disable_device(link); 1778c2ecf20Sopenharmony_ci} /* parport_cs_release */ 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic const struct pcmcia_device_id parport_ids[] = { 1818c2ecf20Sopenharmony_ci PCMCIA_DEVICE_FUNC_ID(3), 1828c2ecf20Sopenharmony_ci PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc), 1838c2ecf20Sopenharmony_ci PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003), 1848c2ecf20Sopenharmony_ci PCMCIA_DEVICE_NULL 1858c2ecf20Sopenharmony_ci}; 1868c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pcmcia, parport_ids); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic struct pcmcia_driver parport_cs_driver = { 1898c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1908c2ecf20Sopenharmony_ci .name = "parport_cs", 1918c2ecf20Sopenharmony_ci .probe = parport_probe, 1928c2ecf20Sopenharmony_ci .remove = parport_detach, 1938c2ecf20Sopenharmony_ci .id_table = parport_ids, 1948c2ecf20Sopenharmony_ci}; 1958c2ecf20Sopenharmony_cimodule_pcmcia_driver(parport_cs_driver); 196