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