brintos

brintos / linux-shallow public Read only

0
0
Text · 12.2 KiB · 0c40526 Raw
521 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * speedfax.c	low level stuff for Sedlbauer Speedfax+ cards4 *		based on the ISAR DSP5 *		Thanks to Sedlbauer AG for informations and HW6 *7 * Author       Karsten Keil <keil@isdn4linux.de>8 *9 * Copyright 2009  by Karsten Keil <keil@isdn4linux.de>10 */11 12#include <linux/interrupt.h>13#include <linux/module.h>14#include <linux/slab.h>15#include <linux/pci.h>16#include <linux/delay.h>17#include <linux/mISDNhw.h>18#include <linux/firmware.h>19#include "ipac.h"20#include "isar.h"21 22#define SPEEDFAX_REV	"2.0"23 24#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID	0x5125#define PCI_SUBVENDOR_SPEEDFAX_PCI	0x5426#define PCI_SUB_ID_SEDLBAUER		0x0127 28#define SFAX_PCI_ADDR		0xc829#define SFAX_PCI_ISAC		0xd030#define SFAX_PCI_ISAR		0xe031 32/* TIGER 100 Registers */33 34#define TIGER_RESET_ADDR	0x0035#define TIGER_EXTERN_RESET_ON	0x0136#define TIGER_EXTERN_RESET_OFF	0x0037#define TIGER_AUX_CTRL		0x0238#define TIGER_AUX_DATA		0x0339#define TIGER_AUX_IRQMASK	0x0540#define TIGER_AUX_STATUS	0x0741 42/* Tiger AUX BITs */43#define SFAX_AUX_IOMASK		0xdd	/* 1 and 5 are inputs */44#define SFAX_ISAR_RESET_BIT_OFF 0x0045#define SFAX_ISAR_RESET_BIT_ON	0x0146#define SFAX_TIGER_IRQ_BIT	0x0247#define SFAX_LED1_BIT		0x0848#define SFAX_LED2_BIT		0x1049 50#define SFAX_PCI_RESET_ON	(SFAX_ISAR_RESET_BIT_ON)51#define SFAX_PCI_RESET_OFF	(SFAX_LED1_BIT | SFAX_LED2_BIT)52 53static int sfax_cnt;54static u32 debug;55static u32 irqloops = 4;56 57struct sfax_hw {58	struct list_head	list;59	struct pci_dev		*pdev;60	char			name[MISDN_MAX_IDLEN];61	u32			irq;62	u32			irqcnt;63	u32			cfg;64	struct _ioport		p_isac;65	struct _ioport		p_isar;66	u8			aux_data;67	spinlock_t		lock;	/* HW access lock */68	struct isac_hw		isac;69	struct isar_hw		isar;70};71 72static LIST_HEAD(Cards);73static DEFINE_RWLOCK(card_lock); /* protect Cards */74 75static void76_set_debug(struct sfax_hw *card)77{78	card->isac.dch.debug = debug;79	card->isar.ch[0].bch.debug = debug;80	card->isar.ch[1].bch.debug = debug;81}82 83static int84set_debug(const char *val, const struct kernel_param *kp)85{86	int ret;87	struct sfax_hw *card;88 89	ret = param_set_uint(val, kp);90	if (!ret) {91		read_lock(&card_lock);92		list_for_each_entry(card, &Cards, list)93			_set_debug(card);94		read_unlock(&card_lock);95	}96	return ret;97}98 99MODULE_AUTHOR("Karsten Keil");100MODULE_DESCRIPTION("mISDN driver for Sedlbauer Speedfax+ cards");101MODULE_LICENSE("GPL v2");102MODULE_VERSION(SPEEDFAX_REV);103MODULE_FIRMWARE("isdn/ISAR.BIN");104module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);105MODULE_PARM_DESC(debug, "Speedfax debug mask");106module_param(irqloops, uint, S_IRUGO | S_IWUSR);107MODULE_PARM_DESC(irqloops, "Speedfax maximal irqloops (default 4)");108 109IOFUNC_IND(ISAC, sfax_hw, p_isac)110IOFUNC_IND(ISAR, sfax_hw, p_isar)111 112static irqreturn_t113speedfax_irq(int intno, void *dev_id)114{115	struct sfax_hw	*sf = dev_id;116	u8 val;117	int cnt = irqloops;118 119	spin_lock(&sf->lock);120	val = inb(sf->cfg + TIGER_AUX_STATUS);121	if (val & SFAX_TIGER_IRQ_BIT) { /* for us or shared ? */122		spin_unlock(&sf->lock);123		return IRQ_NONE; /* shared */124	}125	sf->irqcnt++;126	val = ReadISAR_IND(sf, ISAR_IRQBIT);127Start_ISAR:128	if (val & ISAR_IRQSTA)129		mISDNisar_irq(&sf->isar);130	val = ReadISAC_IND(sf, ISAC_ISTA);131	if (val)132		mISDNisac_irq(&sf->isac, val);133	val = ReadISAR_IND(sf, ISAR_IRQBIT);134	if ((val & ISAR_IRQSTA) && cnt--)135		goto Start_ISAR;136	if (cnt < irqloops)137		pr_debug("%s: %d irqloops cpu%d\n", sf->name,138			 irqloops - cnt, smp_processor_id());139	if (irqloops && !cnt)140		pr_notice("%s: %d IRQ LOOP cpu%d\n", sf->name,141			  irqloops, smp_processor_id());142	spin_unlock(&sf->lock);143	return IRQ_HANDLED;144}145 146static void147enable_hwirq(struct sfax_hw *sf)148{149	WriteISAC_IND(sf, ISAC_MASK, 0);150	WriteISAR_IND(sf, ISAR_IRQBIT, ISAR_IRQMSK);151	outb(SFAX_TIGER_IRQ_BIT, sf->cfg + TIGER_AUX_IRQMASK);152}153 154static void155disable_hwirq(struct sfax_hw *sf)156{157	WriteISAC_IND(sf, ISAC_MASK, 0xFF);158	WriteISAR_IND(sf, ISAR_IRQBIT, 0);159	outb(0, sf->cfg + TIGER_AUX_IRQMASK);160}161 162static void163reset_speedfax(struct sfax_hw *sf)164{165 166	pr_debug("%s: resetting card\n", sf->name);167	outb(TIGER_EXTERN_RESET_ON, sf->cfg + TIGER_RESET_ADDR);168	outb(SFAX_PCI_RESET_ON, sf->cfg + TIGER_AUX_DATA);169	mdelay(1);170	outb(TIGER_EXTERN_RESET_OFF, sf->cfg + TIGER_RESET_ADDR);171	sf->aux_data = SFAX_PCI_RESET_OFF;172	outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);173	mdelay(1);174}175 176static int177sfax_ctrl(struct sfax_hw  *sf, u32 cmd, u_long arg)178{179	int ret = 0;180 181	switch (cmd) {182	case HW_RESET_REQ:183		reset_speedfax(sf);184		break;185	case HW_ACTIVATE_IND:186		if (arg & 1)187			sf->aux_data &= ~SFAX_LED1_BIT;188		if (arg & 2)189			sf->aux_data &= ~SFAX_LED2_BIT;190		outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);191		break;192	case HW_DEACT_IND:193		if (arg & 1)194			sf->aux_data |= SFAX_LED1_BIT;195		if (arg & 2)196			sf->aux_data |= SFAX_LED2_BIT;197		outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);198		break;199	default:200		pr_info("%s: %s unknown command %x %lx\n",201			sf->name, __func__, cmd, arg);202		ret = -EINVAL;203		break;204	}205	return ret;206}207 208static int209channel_ctrl(struct sfax_hw  *sf, struct mISDN_ctrl_req *cq)210{211	int	ret = 0;212 213	switch (cq->op) {214	case MISDN_CTRL_GETOP:215		cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3;216		break;217	case MISDN_CTRL_LOOP:218		/* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */219		if (cq->channel < 0 || cq->channel > 3) {220			ret = -EINVAL;221			break;222		}223		ret = sf->isac.ctrl(&sf->isac, HW_TESTLOOP, cq->channel);224		break;225	case MISDN_CTRL_L1_TIMER3:226		ret = sf->isac.ctrl(&sf->isac, HW_TIMER3_VALUE, cq->p1);227		break;228	default:229		pr_info("%s: unknown Op %x\n", sf->name, cq->op);230		ret = -EINVAL;231		break;232	}233	return ret;234}235 236static int237sfax_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)238{239	struct mISDNdevice	*dev = container_of(ch, struct mISDNdevice, D);240	struct dchannel		*dch = container_of(dev, struct dchannel, dev);241	struct sfax_hw		*sf = dch->hw;242	struct channel_req	*rq;243	int			err = 0;244 245	pr_debug("%s: cmd:%x %p\n", sf->name, cmd, arg);246	switch (cmd) {247	case OPEN_CHANNEL:248		rq = arg;249		if (rq->protocol == ISDN_P_TE_S0)250			err = sf->isac.open(&sf->isac, rq);251		else252			err = sf->isar.open(&sf->isar, rq);253		if (err)254			break;255		if (!try_module_get(THIS_MODULE))256			pr_info("%s: cannot get module\n", sf->name);257		break;258	case CLOSE_CHANNEL:259		pr_debug("%s: dev(%d) close from %p\n", sf->name,260			 dch->dev.id, __builtin_return_address(0));261		module_put(THIS_MODULE);262		break;263	case CONTROL_CHANNEL:264		err = channel_ctrl(sf, arg);265		break;266	default:267		pr_debug("%s: unknown command %x\n", sf->name, cmd);268		return -EINVAL;269	}270	return err;271}272 273static int274init_card(struct sfax_hw *sf)275{276	int	ret, cnt = 3;277	u_long	flags;278 279	ret = request_irq(sf->irq, speedfax_irq, IRQF_SHARED, sf->name, sf);280	if (ret) {281		pr_info("%s: couldn't get interrupt %d\n", sf->name, sf->irq);282		return ret;283	}284	while (cnt--) {285		spin_lock_irqsave(&sf->lock, flags);286		ret = sf->isac.init(&sf->isac);287		if (ret) {288			spin_unlock_irqrestore(&sf->lock, flags);289			pr_info("%s: ISAC init failed with %d\n",290				sf->name, ret);291			break;292		}293		enable_hwirq(sf);294		/* RESET Receiver and Transmitter */295		WriteISAC_IND(sf, ISAC_CMDR, 0x41);296		spin_unlock_irqrestore(&sf->lock, flags);297		msleep_interruptible(10);298		if (debug & DEBUG_HW)299			pr_notice("%s: IRQ %d count %d\n", sf->name,300				  sf->irq, sf->irqcnt);301		if (!sf->irqcnt) {302			pr_info("%s: IRQ(%d) got no requests during init %d\n",303				sf->name, sf->irq, 3 - cnt);304		} else305			return 0;306	}307	free_irq(sf->irq, sf);308	return -EIO;309}310 311 312static int313setup_speedfax(struct sfax_hw *sf)314{315	u_long flags;316 317	if (!request_region(sf->cfg, 256, sf->name)) {318		pr_info("mISDN: %s config port %x-%x already in use\n",319			sf->name, sf->cfg, sf->cfg + 255);320		return -EIO;321	}322	outb(0xff, sf->cfg);323	outb(0, sf->cfg);324	outb(0xdd, sf->cfg + TIGER_AUX_CTRL);325	outb(0, sf->cfg + TIGER_AUX_IRQMASK);326 327	sf->isac.type = IPAC_TYPE_ISAC;328	sf->p_isac.ale = sf->cfg + SFAX_PCI_ADDR;329	sf->p_isac.port = sf->cfg + SFAX_PCI_ISAC;330	sf->p_isar.ale = sf->cfg + SFAX_PCI_ADDR;331	sf->p_isar.port = sf->cfg + SFAX_PCI_ISAR;332	ASSIGN_FUNC(IND, ISAC, sf->isac);333	ASSIGN_FUNC(IND, ISAR, sf->isar);334	spin_lock_irqsave(&sf->lock, flags);335	reset_speedfax(sf);336	disable_hwirq(sf);337	spin_unlock_irqrestore(&sf->lock, flags);338	return 0;339}340 341static void342release_card(struct sfax_hw *card) {343	u_long	flags;344 345	spin_lock_irqsave(&card->lock, flags);346	disable_hwirq(card);347	spin_unlock_irqrestore(&card->lock, flags);348	card->isac.release(&card->isac);349	free_irq(card->irq, card);350	card->isar.release(&card->isar);351	mISDN_unregister_device(&card->isac.dch.dev);352	release_region(card->cfg, 256);353	pci_disable_device(card->pdev);354	pci_set_drvdata(card->pdev, NULL);355	write_lock_irqsave(&card_lock, flags);356	list_del(&card->list);357	write_unlock_irqrestore(&card_lock, flags);358	kfree(card);359	sfax_cnt--;360}361 362static int363setup_instance(struct sfax_hw *card)364{365	const struct firmware *firmware;366	int i, err;367	u_long flags;368 369	snprintf(card->name, MISDN_MAX_IDLEN - 1, "Speedfax.%d", sfax_cnt + 1);370	write_lock_irqsave(&card_lock, flags);371	list_add_tail(&card->list, &Cards);372	write_unlock_irqrestore(&card_lock, flags);373	_set_debug(card);374	spin_lock_init(&card->lock);375	card->isac.hwlock = &card->lock;376	card->isar.hwlock = &card->lock;377	card->isar.ctrl = (void *)&sfax_ctrl;378	card->isac.name = card->name;379	card->isar.name = card->name;380	card->isar.owner = THIS_MODULE;381 382	err = request_firmware(&firmware, "isdn/ISAR.BIN", &card->pdev->dev);383	if (err < 0) {384		pr_info("%s: firmware request failed %d\n",385			card->name, err);386		goto error_fw;387	}388	if (debug & DEBUG_HW)389		pr_notice("%s: got firmware %zu bytes\n",390			  card->name, firmware->size);391 392	mISDNisac_init(&card->isac, card);393 394	card->isac.dch.dev.D.ctrl = sfax_dctrl;395	card->isac.dch.dev.Bprotocols =396		mISDNisar_init(&card->isar, card);397	for (i = 0; i < 2; i++) {398		set_channelmap(i + 1, card->isac.dch.dev.channelmap);399		list_add(&card->isar.ch[i].bch.ch.list,400			 &card->isac.dch.dev.bchannels);401	}402 403	err = setup_speedfax(card);404	if (err)405		goto error_setup;406	err = card->isar.init(&card->isar);407	if (err)408		goto error;409	err = mISDN_register_device(&card->isac.dch.dev,410				    &card->pdev->dev, card->name);411	if (err)412		goto error;413	err = init_card(card);414	if (err)415		goto error_init;416	err = card->isar.firmware(&card->isar, firmware->data, firmware->size);417	if (!err)  {418		release_firmware(firmware);419		sfax_cnt++;420		pr_notice("SpeedFax %d cards installed\n", sfax_cnt);421		return 0;422	}423	disable_hwirq(card);424	free_irq(card->irq, card);425error_init:426	mISDN_unregister_device(&card->isac.dch.dev);427error:428	release_region(card->cfg, 256);429error_setup:430	card->isac.release(&card->isac);431	card->isar.release(&card->isar);432	release_firmware(firmware);433error_fw:434	pci_disable_device(card->pdev);435	write_lock_irqsave(&card_lock, flags);436	list_del(&card->list);437	write_unlock_irqrestore(&card_lock, flags);438	kfree(card);439	return err;440}441 442static int443sfaxpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)444{445	int err = -ENOMEM;446	struct sfax_hw *card = kzalloc(sizeof(struct sfax_hw), GFP_KERNEL);447 448	if (!card) {449		pr_info("No memory for Speedfax+ PCI\n");450		return err;451	}452	card->pdev = pdev;453	err = pci_enable_device(pdev);454	if (err) {455		kfree(card);456		return err;457	}458 459	pr_notice("mISDN: Speedfax found adapter %s at %s\n",460		  (char *)ent->driver_data, pci_name(pdev));461 462	card->cfg = pci_resource_start(pdev, 0);463	card->irq = pdev->irq;464	pci_set_drvdata(pdev, card);465	err = setup_instance(card);466	if (err)467		pci_set_drvdata(pdev, NULL);468	return err;469}470 471static void472sfax_remove_pci(struct pci_dev *pdev)473{474	struct sfax_hw	*card = pci_get_drvdata(pdev);475 476	if (card)477		release_card(card);478	else479		pr_debug("%s: drvdata already removed\n", __func__);480}481 482static struct pci_device_id sfaxpci_ids[] = {483	{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,484	  PCI_SUBVENDOR_SPEEDFAX_PYRAMID, PCI_SUB_ID_SEDLBAUER,485	  0, 0, (unsigned long) "Pyramid Speedfax + PCI"486	},487	{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,488	  PCI_SUBVENDOR_SPEEDFAX_PCI, PCI_SUB_ID_SEDLBAUER,489	  0, 0, (unsigned long) "Sedlbauer Speedfax + PCI"490	},491	{ }492};493MODULE_DEVICE_TABLE(pci, sfaxpci_ids);494 495static struct pci_driver sfaxpci_driver = {496	.name = "speedfax+ pci",497	.probe = sfaxpci_probe,498	.remove = sfax_remove_pci,499	.id_table = sfaxpci_ids,500};501 502static int __init503Speedfax_init(void)504{505	int err;506 507	pr_notice("Sedlbauer Speedfax+ Driver Rev. %s\n",508		  SPEEDFAX_REV);509	err = pci_register_driver(&sfaxpci_driver);510	return err;511}512 513static void __exit514Speedfax_cleanup(void)515{516	pci_unregister_driver(&sfaxpci_driver);517}518 519module_init(Speedfax_init);520module_exit(Speedfax_cleanup);521