diff options
Diffstat (limited to 'drivers/net/irda')
-rw-r--r-- | drivers/net/irda/Kconfig | 20 | ||||
-rw-r--r-- | drivers/net/irda/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/irda/irda-usb.c | 8 | ||||
-rw-r--r-- | drivers/net/irda/sir-dev.h | 13 | ||||
-rw-r--r-- | drivers/net/irda/sir_dev.c | 315 | ||||
-rw-r--r-- | drivers/net/irda/sir_kthread.c | 508 | ||||
-rw-r--r-- | drivers/net/irda/smsc-ircc2.c | 330 |
7 files changed, 606 insertions, 590 deletions
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index 5e6d00752990..cff8598aa800 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig | |||
@@ -33,7 +33,7 @@ config DONGLE | |||
33 | 33 | ||
34 | config ESI_DONGLE | 34 | config ESI_DONGLE |
35 | tristate "ESI JetEye PC dongle" | 35 | tristate "ESI JetEye PC dongle" |
36 | depends on DONGLE && IRDA | 36 | depends on IRTTY_SIR && DONGLE && IRDA |
37 | help | 37 | help |
38 | Say Y here if you want to build support for the Extended Systems | 38 | Say Y here if you want to build support for the Extended Systems |
39 | JetEye PC dongle. To compile it as a module, choose M here. The ESI | 39 | JetEye PC dongle. To compile it as a module, choose M here. The ESI |
@@ -44,7 +44,7 @@ config ESI_DONGLE | |||
44 | 44 | ||
45 | config ACTISYS_DONGLE | 45 | config ACTISYS_DONGLE |
46 | tristate "ACTiSYS IR-220L and IR220L+ dongle" | 46 | tristate "ACTiSYS IR-220L and IR220L+ dongle" |
47 | depends on DONGLE && IRDA | 47 | depends on IRTTY_SIR && DONGLE && IRDA |
48 | help | 48 | help |
49 | Say Y here if you want to build support for the ACTiSYS IR-220L and | 49 | Say Y here if you want to build support for the ACTiSYS IR-220L and |
50 | IR220L+ dongles. To compile it as a module, choose M here. The | 50 | IR220L+ dongles. To compile it as a module, choose M here. The |
@@ -55,7 +55,7 @@ config ACTISYS_DONGLE | |||
55 | 55 | ||
56 | config TEKRAM_DONGLE | 56 | config TEKRAM_DONGLE |
57 | tristate "Tekram IrMate 210B dongle" | 57 | tristate "Tekram IrMate 210B dongle" |
58 | depends on DONGLE && IRDA | 58 | depends on IRTTY_SIR && DONGLE && IRDA |
59 | help | 59 | help |
60 | Say Y here if you want to build support for the Tekram IrMate 210B | 60 | Say Y here if you want to build support for the Tekram IrMate 210B |
61 | dongle. To compile it as a module, choose M here. The Tekram dongle | 61 | dongle. To compile it as a module, choose M here. The Tekram dongle |
@@ -66,7 +66,7 @@ config TEKRAM_DONGLE | |||
66 | 66 | ||
67 | config TOIM3232_DONGLE | 67 | config TOIM3232_DONGLE |
68 | tristate "TOIM3232 IrDa dongle" | 68 | tristate "TOIM3232 IrDa dongle" |
69 | depends on DONGLE && IRDA | 69 | depends on IRTTY_SIR && DONGLE && IRDA |
70 | help | 70 | help |
71 | Say Y here if you want to build support for the Vishay/Temic | 71 | Say Y here if you want to build support for the Vishay/Temic |
72 | TOIM3232 and TOIM4232 based dongles. | 72 | TOIM3232 and TOIM4232 based dongles. |
@@ -74,7 +74,7 @@ config TOIM3232_DONGLE | |||
74 | 74 | ||
75 | config LITELINK_DONGLE | 75 | config LITELINK_DONGLE |
76 | tristate "Parallax LiteLink dongle" | 76 | tristate "Parallax LiteLink dongle" |
77 | depends on DONGLE && IRDA | 77 | depends on IRTTY_SIR && DONGLE && IRDA |
78 | help | 78 | help |
79 | Say Y here if you want to build support for the Parallax Litelink | 79 | Say Y here if you want to build support for the Parallax Litelink |
80 | dongle. To compile it as a module, choose M here. The Parallax | 80 | dongle. To compile it as a module, choose M here. The Parallax |
@@ -85,7 +85,7 @@ config LITELINK_DONGLE | |||
85 | 85 | ||
86 | config MA600_DONGLE | 86 | config MA600_DONGLE |
87 | tristate "Mobile Action MA600 dongle" | 87 | tristate "Mobile Action MA600 dongle" |
88 | depends on DONGLE && IRDA && EXPERIMENTAL | 88 | depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL |
89 | help | 89 | help |
90 | Say Y here if you want to build support for the Mobile Action MA600 | 90 | Say Y here if you want to build support for the Mobile Action MA600 |
91 | dongle. To compile it as a module, choose M here. The MA600 dongle | 91 | dongle. To compile it as a module, choose M here. The MA600 dongle |
@@ -98,7 +98,7 @@ config MA600_DONGLE | |||
98 | 98 | ||
99 | config GIRBIL_DONGLE | 99 | config GIRBIL_DONGLE |
100 | tristate "Greenwich GIrBIL dongle" | 100 | tristate "Greenwich GIrBIL dongle" |
101 | depends on DONGLE && IRDA && EXPERIMENTAL | 101 | depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL |
102 | help | 102 | help |
103 | Say Y here if you want to build support for the Greenwich GIrBIL | 103 | Say Y here if you want to build support for the Greenwich GIrBIL |
104 | dongle. If you want to compile it as a module, choose M here. | 104 | dongle. If you want to compile it as a module, choose M here. |
@@ -109,7 +109,7 @@ config GIRBIL_DONGLE | |||
109 | 109 | ||
110 | config MCP2120_DONGLE | 110 | config MCP2120_DONGLE |
111 | tristate "Microchip MCP2120" | 111 | tristate "Microchip MCP2120" |
112 | depends on DONGLE && IRDA && EXPERIMENTAL | 112 | depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL |
113 | help | 113 | help |
114 | Say Y here if you want to build support for the Microchip MCP2120 | 114 | Say Y here if you want to build support for the Microchip MCP2120 |
115 | dongle. If you want to compile it as a module, choose M here. | 115 | dongle. If you want to compile it as a module, choose M here. |
@@ -123,7 +123,7 @@ config MCP2120_DONGLE | |||
123 | 123 | ||
124 | config OLD_BELKIN_DONGLE | 124 | config OLD_BELKIN_DONGLE |
125 | tristate "Old Belkin dongle" | 125 | tristate "Old Belkin dongle" |
126 | depends on DONGLE && IRDA && EXPERIMENTAL | 126 | depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL |
127 | help | 127 | help |
128 | Say Y here if you want to build support for the Adaptec Airport 1000 | 128 | Say Y here if you want to build support for the Adaptec Airport 1000 |
129 | and 2000 dongles. If you want to compile it as a module, choose | 129 | and 2000 dongles. If you want to compile it as a module, choose |
@@ -132,7 +132,7 @@ config OLD_BELKIN_DONGLE | |||
132 | 132 | ||
133 | config ACT200L_DONGLE | 133 | config ACT200L_DONGLE |
134 | tristate "ACTiSYS IR-200L dongle" | 134 | tristate "ACTiSYS IR-200L dongle" |
135 | depends on DONGLE && IRDA && EXPERIMENTAL | 135 | depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL |
136 | help | 136 | help |
137 | Say Y here if you want to build support for the ACTiSYS IR-200L | 137 | Say Y here if you want to build support for the ACTiSYS IR-200L |
138 | dongle. If you want to compile it as a module, choose M here. | 138 | dongle. If you want to compile it as a module, choose M here. |
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 27ab75f20799..c1ce2398efea 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile | |||
@@ -46,4 +46,4 @@ obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o | |||
46 | obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o | 46 | obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o |
47 | 47 | ||
48 | # The SIR helper module | 48 | # The SIR helper module |
49 | sir-dev-objs := sir_dev.o sir_dongle.o sir_kthread.o | 49 | sir-dev-objs := sir_dev.o sir_dongle.o |
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 606243d11793..cd87593e4e8a 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c | |||
@@ -1778,7 +1778,7 @@ static int irda_usb_probe(struct usb_interface *intf, | |||
1778 | 1778 | ||
1779 | if (self->needspatch) { | 1779 | if (self->needspatch) { |
1780 | ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0), | 1780 | ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0), |
1781 | 0x02, 0x40, 0, 0, 0, 0, msecs_to_jiffies(500)); | 1781 | 0x02, 0x40, 0, 0, NULL, 0, 500); |
1782 | if (ret < 0) { | 1782 | if (ret < 0) { |
1783 | IRDA_DEBUG (0, "usb_control_msg failed %d\n", ret); | 1783 | IRDA_DEBUG (0, "usb_control_msg failed %d\n", ret); |
1784 | goto err_out_3; | 1784 | goto err_out_3; |
@@ -1815,14 +1815,14 @@ static int irda_usb_probe(struct usb_interface *intf, | |||
1815 | self->needspatch = (ret < 0); | 1815 | self->needspatch = (ret < 0); |
1816 | if (ret < 0) { | 1816 | if (ret < 0) { |
1817 | printk("patch_device failed\n"); | 1817 | printk("patch_device failed\n"); |
1818 | goto err_out_4; | 1818 | goto err_out_5; |
1819 | } | 1819 | } |
1820 | 1820 | ||
1821 | /* replace IrDA class descriptor with what patched device is now reporting */ | 1821 | /* replace IrDA class descriptor with what patched device is now reporting */ |
1822 | irda_desc = irda_usb_find_class_desc (self->usbintf); | 1822 | irda_desc = irda_usb_find_class_desc (self->usbintf); |
1823 | if (irda_desc == NULL) { | 1823 | if (irda_desc == NULL) { |
1824 | ret = -ENODEV; | 1824 | ret = -ENODEV; |
1825 | goto err_out_4; | 1825 | goto err_out_5; |
1826 | } | 1826 | } |
1827 | if (self->irda_desc) | 1827 | if (self->irda_desc) |
1828 | kfree (self->irda_desc); | 1828 | kfree (self->irda_desc); |
@@ -1832,6 +1832,8 @@ static int irda_usb_probe(struct usb_interface *intf, | |||
1832 | 1832 | ||
1833 | return 0; | 1833 | return 0; |
1834 | 1834 | ||
1835 | err_out_5: | ||
1836 | unregister_netdev(self->netdev); | ||
1835 | err_out_4: | 1837 | err_out_4: |
1836 | kfree(self->speed_buff); | 1838 | kfree(self->speed_buff); |
1837 | err_out_3: | 1839 | err_out_3: |
diff --git a/drivers/net/irda/sir-dev.h b/drivers/net/irda/sir-dev.h index f69fb4cec76f..9fa294a546d6 100644 --- a/drivers/net/irda/sir-dev.h +++ b/drivers/net/irda/sir-dev.h | |||
@@ -15,23 +15,14 @@ | |||
15 | #define IRDA_SIR_H | 15 | #define IRDA_SIR_H |
16 | 16 | ||
17 | #include <linux/netdevice.h> | 17 | #include <linux/netdevice.h> |
18 | #include <linux/workqueue.h> | ||
18 | 19 | ||
19 | #include <net/irda/irda.h> | 20 | #include <net/irda/irda.h> |
20 | #include <net/irda/irda_device.h> // iobuff_t | 21 | #include <net/irda/irda_device.h> // iobuff_t |
21 | 22 | ||
22 | /* FIXME: unify irda_request with sir_fsm! */ | ||
23 | |||
24 | struct irda_request { | ||
25 | struct list_head lh_request; | ||
26 | unsigned long pending; | ||
27 | void (*func)(void *); | ||
28 | void *data; | ||
29 | struct timer_list timer; | ||
30 | }; | ||
31 | |||
32 | struct sir_fsm { | 23 | struct sir_fsm { |
33 | struct semaphore sem; | 24 | struct semaphore sem; |
34 | struct irda_request rq; | 25 | struct work_struct work; |
35 | unsigned state, substate; | 26 | unsigned state, substate; |
36 | int param; | 27 | int param; |
37 | int result; | 28 | int result; |
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index ea7c9464d46a..3b5854d10c17 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c | |||
@@ -23,6 +23,298 @@ | |||
23 | 23 | ||
24 | #include "sir-dev.h" | 24 | #include "sir-dev.h" |
25 | 25 | ||
26 | |||
27 | static struct workqueue_struct *irda_sir_wq; | ||
28 | |||
29 | /* STATE MACHINE */ | ||
30 | |||
31 | /* substate handler of the config-fsm to handle the cases where we want | ||
32 | * to wait for transmit completion before changing the port configuration | ||
33 | */ | ||
34 | |||
35 | static int sirdev_tx_complete_fsm(struct sir_dev *dev) | ||
36 | { | ||
37 | struct sir_fsm *fsm = &dev->fsm; | ||
38 | unsigned next_state, delay; | ||
39 | unsigned bytes_left; | ||
40 | |||
41 | do { | ||
42 | next_state = fsm->substate; /* default: stay in current substate */ | ||
43 | delay = 0; | ||
44 | |||
45 | switch(fsm->substate) { | ||
46 | |||
47 | case SIRDEV_STATE_WAIT_XMIT: | ||
48 | if (dev->drv->chars_in_buffer) | ||
49 | bytes_left = dev->drv->chars_in_buffer(dev); | ||
50 | else | ||
51 | bytes_left = 0; | ||
52 | if (!bytes_left) { | ||
53 | next_state = SIRDEV_STATE_WAIT_UNTIL_SENT; | ||
54 | break; | ||
55 | } | ||
56 | |||
57 | if (dev->speed > 115200) | ||
58 | delay = (bytes_left*8*10000) / (dev->speed/100); | ||
59 | else if (dev->speed > 0) | ||
60 | delay = (bytes_left*10*10000) / (dev->speed/100); | ||
61 | else | ||
62 | delay = 0; | ||
63 | /* expected delay (usec) until remaining bytes are sent */ | ||
64 | if (delay < 100) { | ||
65 | udelay(delay); | ||
66 | delay = 0; | ||
67 | break; | ||
68 | } | ||
69 | /* sleep some longer delay (msec) */ | ||
70 | delay = (delay+999) / 1000; | ||
71 | break; | ||
72 | |||
73 | case SIRDEV_STATE_WAIT_UNTIL_SENT: | ||
74 | /* block until underlaying hardware buffer are empty */ | ||
75 | if (dev->drv->wait_until_sent) | ||
76 | dev->drv->wait_until_sent(dev); | ||
77 | next_state = SIRDEV_STATE_TX_DONE; | ||
78 | break; | ||
79 | |||
80 | case SIRDEV_STATE_TX_DONE: | ||
81 | return 0; | ||
82 | |||
83 | default: | ||
84 | IRDA_ERROR("%s - undefined state\n", __FUNCTION__); | ||
85 | return -EINVAL; | ||
86 | } | ||
87 | fsm->substate = next_state; | ||
88 | } while (delay == 0); | ||
89 | return delay; | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * Function sirdev_config_fsm | ||
94 | * | ||
95 | * State machine to handle the configuration of the device (and attached dongle, if any). | ||
96 | * This handler is scheduled for execution in kIrDAd context, so we can sleep. | ||
97 | * however, kIrDAd is shared by all sir_dev devices so we better don't sleep there too | ||
98 | * long. Instead, for longer delays we start a timer to reschedule us later. | ||
99 | * On entry, fsm->sem is always locked and the netdev xmit queue stopped. | ||
100 | * Both must be unlocked/restarted on completion - but only on final exit. | ||
101 | */ | ||
102 | |||
103 | static void sirdev_config_fsm(void *data) | ||
104 | { | ||
105 | struct sir_dev *dev = data; | ||
106 | struct sir_fsm *fsm = &dev->fsm; | ||
107 | int next_state; | ||
108 | int ret = -1; | ||
109 | unsigned delay; | ||
110 | |||
111 | IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); | ||
112 | |||
113 | do { | ||
114 | IRDA_DEBUG(3, "%s - state=0x%04x / substate=0x%04x\n", | ||
115 | __FUNCTION__, fsm->state, fsm->substate); | ||
116 | |||
117 | next_state = fsm->state; | ||
118 | delay = 0; | ||
119 | |||
120 | switch(fsm->state) { | ||
121 | |||
122 | case SIRDEV_STATE_DONGLE_OPEN: | ||
123 | if (dev->dongle_drv != NULL) { | ||
124 | ret = sirdev_put_dongle(dev); | ||
125 | if (ret) { | ||
126 | fsm->result = -EINVAL; | ||
127 | next_state = SIRDEV_STATE_ERROR; | ||
128 | break; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | /* Initialize dongle */ | ||
133 | ret = sirdev_get_dongle(dev, fsm->param); | ||
134 | if (ret) { | ||
135 | fsm->result = ret; | ||
136 | next_state = SIRDEV_STATE_ERROR; | ||
137 | break; | ||
138 | } | ||
139 | |||
140 | /* Dongles are powered through the modem control lines which | ||
141 | * were just set during open. Before resetting, let's wait for | ||
142 | * the power to stabilize. This is what some dongle drivers did | ||
143 | * in open before, while others didn't - should be safe anyway. | ||
144 | */ | ||
145 | |||
146 | delay = 50; | ||
147 | fsm->substate = SIRDEV_STATE_DONGLE_RESET; | ||
148 | next_state = SIRDEV_STATE_DONGLE_RESET; | ||
149 | |||
150 | fsm->param = 9600; | ||
151 | |||
152 | break; | ||
153 | |||
154 | case SIRDEV_STATE_DONGLE_CLOSE: | ||
155 | /* shouldn't we just treat this as success=? */ | ||
156 | if (dev->dongle_drv == NULL) { | ||
157 | fsm->result = -EINVAL; | ||
158 | next_state = SIRDEV_STATE_ERROR; | ||
159 | break; | ||
160 | } | ||
161 | |||
162 | ret = sirdev_put_dongle(dev); | ||
163 | if (ret) { | ||
164 | fsm->result = ret; | ||
165 | next_state = SIRDEV_STATE_ERROR; | ||
166 | break; | ||
167 | } | ||
168 | next_state = SIRDEV_STATE_DONE; | ||
169 | break; | ||
170 | |||
171 | case SIRDEV_STATE_SET_DTR_RTS: | ||
172 | ret = sirdev_set_dtr_rts(dev, | ||
173 | (fsm->param&0x02) ? TRUE : FALSE, | ||
174 | (fsm->param&0x01) ? TRUE : FALSE); | ||
175 | next_state = SIRDEV_STATE_DONE; | ||
176 | break; | ||
177 | |||
178 | case SIRDEV_STATE_SET_SPEED: | ||
179 | fsm->substate = SIRDEV_STATE_WAIT_XMIT; | ||
180 | next_state = SIRDEV_STATE_DONGLE_CHECK; | ||
181 | break; | ||
182 | |||
183 | case SIRDEV_STATE_DONGLE_CHECK: | ||
184 | ret = sirdev_tx_complete_fsm(dev); | ||
185 | if (ret < 0) { | ||
186 | fsm->result = ret; | ||
187 | next_state = SIRDEV_STATE_ERROR; | ||
188 | break; | ||
189 | } | ||
190 | if ((delay=ret) != 0) | ||
191 | break; | ||
192 | |||
193 | if (dev->dongle_drv) { | ||
194 | fsm->substate = SIRDEV_STATE_DONGLE_RESET; | ||
195 | next_state = SIRDEV_STATE_DONGLE_RESET; | ||
196 | } | ||
197 | else { | ||
198 | dev->speed = fsm->param; | ||
199 | next_state = SIRDEV_STATE_PORT_SPEED; | ||
200 | } | ||
201 | break; | ||
202 | |||
203 | case SIRDEV_STATE_DONGLE_RESET: | ||
204 | if (dev->dongle_drv->reset) { | ||
205 | ret = dev->dongle_drv->reset(dev); | ||
206 | if (ret < 0) { | ||
207 | fsm->result = ret; | ||
208 | next_state = SIRDEV_STATE_ERROR; | ||
209 | break; | ||
210 | } | ||
211 | } | ||
212 | else | ||
213 | ret = 0; | ||
214 | if ((delay=ret) == 0) { | ||
215 | /* set serial port according to dongle default speed */ | ||
216 | if (dev->drv->set_speed) | ||
217 | dev->drv->set_speed(dev, dev->speed); | ||
218 | fsm->substate = SIRDEV_STATE_DONGLE_SPEED; | ||
219 | next_state = SIRDEV_STATE_DONGLE_SPEED; | ||
220 | } | ||
221 | break; | ||
222 | |||
223 | case SIRDEV_STATE_DONGLE_SPEED: | ||
224 | if (dev->dongle_drv->reset) { | ||
225 | ret = dev->dongle_drv->set_speed(dev, fsm->param); | ||
226 | if (ret < 0) { | ||
227 | fsm->result = ret; | ||
228 | next_state = SIRDEV_STATE_ERROR; | ||
229 | break; | ||
230 | } | ||
231 | } | ||
232 | else | ||
233 | ret = 0; | ||
234 | if ((delay=ret) == 0) | ||
235 | next_state = SIRDEV_STATE_PORT_SPEED; | ||
236 | break; | ||
237 | |||
238 | case SIRDEV_STATE_PORT_SPEED: | ||
239 | /* Finally we are ready to change the serial port speed */ | ||
240 | if (dev->drv->set_speed) | ||
241 | dev->drv->set_speed(dev, dev->speed); | ||
242 | dev->new_speed = 0; | ||
243 | next_state = SIRDEV_STATE_DONE; | ||
244 | break; | ||
245 | |||
246 | case SIRDEV_STATE_DONE: | ||
247 | /* Signal network layer so it can send more frames */ | ||
248 | netif_wake_queue(dev->netdev); | ||
249 | next_state = SIRDEV_STATE_COMPLETE; | ||
250 | break; | ||
251 | |||
252 | default: | ||
253 | IRDA_ERROR("%s - undefined state\n", __FUNCTION__); | ||
254 | fsm->result = -EINVAL; | ||
255 | /* fall thru */ | ||
256 | |||
257 | case SIRDEV_STATE_ERROR: | ||
258 | IRDA_ERROR("%s - error: %d\n", __FUNCTION__, fsm->result); | ||
259 | |||
260 | #if 0 /* don't enable this before we have netdev->tx_timeout to recover */ | ||
261 | netif_stop_queue(dev->netdev); | ||
262 | #else | ||
263 | netif_wake_queue(dev->netdev); | ||
264 | #endif | ||
265 | /* fall thru */ | ||
266 | |||
267 | case SIRDEV_STATE_COMPLETE: | ||
268 | /* config change finished, so we are not busy any longer */ | ||
269 | sirdev_enable_rx(dev); | ||
270 | up(&fsm->sem); | ||
271 | return; | ||
272 | } | ||
273 | fsm->state = next_state; | ||
274 | } while(!delay); | ||
275 | |||
276 | queue_delayed_work(irda_sir_wq, &fsm->work, msecs_to_jiffies(delay)); | ||
277 | } | ||
278 | |||
279 | /* schedule some device configuration task for execution by kIrDAd | ||
280 | * on behalf of the above state machine. | ||
281 | * can be called from process or interrupt/tasklet context. | ||
282 | */ | ||
283 | |||
284 | int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned param) | ||
285 | { | ||
286 | struct sir_fsm *fsm = &dev->fsm; | ||
287 | |||
288 | IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param); | ||
289 | |||
290 | if (down_trylock(&fsm->sem)) { | ||
291 | if (in_interrupt() || in_atomic() || irqs_disabled()) { | ||
292 | IRDA_DEBUG(1, "%s(), state machine busy!\n", __FUNCTION__); | ||
293 | return -EWOULDBLOCK; | ||
294 | } else | ||
295 | down(&fsm->sem); | ||
296 | } | ||
297 | |||
298 | if (fsm->state == SIRDEV_STATE_DEAD) { | ||
299 | /* race with sirdev_close should never happen */ | ||
300 | IRDA_ERROR("%s(), instance staled!\n", __FUNCTION__); | ||
301 | up(&fsm->sem); | ||
302 | return -ESTALE; /* or better EPIPE? */ | ||
303 | } | ||
304 | |||
305 | netif_stop_queue(dev->netdev); | ||
306 | atomic_set(&dev->enable_rx, 0); | ||
307 | |||
308 | fsm->state = initial_state; | ||
309 | fsm->param = param; | ||
310 | fsm->result = 0; | ||
311 | |||
312 | INIT_WORK(&fsm->work, sirdev_config_fsm, dev); | ||
313 | queue_work(irda_sir_wq, &fsm->work); | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | |||
26 | /***************************************************************************/ | 318 | /***************************************************************************/ |
27 | 319 | ||
28 | void sirdev_enable_rx(struct sir_dev *dev) | 320 | void sirdev_enable_rx(struct sir_dev *dev) |
@@ -619,10 +911,6 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n | |||
619 | spin_lock_init(&dev->tx_lock); | 911 | spin_lock_init(&dev->tx_lock); |
620 | init_MUTEX(&dev->fsm.sem); | 912 | init_MUTEX(&dev->fsm.sem); |
621 | 913 | ||
622 | INIT_LIST_HEAD(&dev->fsm.rq.lh_request); | ||
623 | dev->fsm.rq.pending = 0; | ||
624 | init_timer(&dev->fsm.rq.timer); | ||
625 | |||
626 | dev->drv = drv; | 914 | dev->drv = drv; |
627 | dev->netdev = ndev; | 915 | dev->netdev = ndev; |
628 | 916 | ||
@@ -682,3 +970,22 @@ int sirdev_put_instance(struct sir_dev *dev) | |||
682 | } | 970 | } |
683 | EXPORT_SYMBOL(sirdev_put_instance); | 971 | EXPORT_SYMBOL(sirdev_put_instance); |
684 | 972 | ||
973 | static int __init sir_wq_init(void) | ||
974 | { | ||
975 | irda_sir_wq = create_singlethread_workqueue("irda_sir_wq"); | ||
976 | if (!irda_sir_wq) | ||
977 | return -ENOMEM; | ||
978 | return 0; | ||
979 | } | ||
980 | |||
981 | static void __exit sir_wq_exit(void) | ||
982 | { | ||
983 | destroy_workqueue(irda_sir_wq); | ||
984 | } | ||
985 | |||
986 | module_init(sir_wq_init); | ||
987 | module_exit(sir_wq_exit); | ||
988 | |||
989 | MODULE_AUTHOR("Martin Diehl <info@mdiehl.de>"); | ||
990 | MODULE_DESCRIPTION("IrDA SIR core"); | ||
991 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/irda/sir_kthread.c b/drivers/net/irda/sir_kthread.c deleted file mode 100644 index e3904d6bfecd..000000000000 --- a/drivers/net/irda/sir_kthread.c +++ /dev/null | |||
@@ -1,508 +0,0 @@ | |||
1 | /********************************************************************* | ||
2 | * | ||
3 | * sir_kthread.c: dedicated thread to process scheduled | ||
4 | * sir device setup requests | ||
5 | * | ||
6 | * Copyright (c) 2002 Martin Diehl | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License as | ||
10 | * published by the Free Software Foundation; either version 2 of | ||
11 | * the License, or (at your option) any later version. | ||
12 | * | ||
13 | ********************************************************************/ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/version.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/smp_lock.h> | ||
20 | #include <linux/completion.h> | ||
21 | #include <linux/delay.h> | ||
22 | |||
23 | #include <net/irda/irda.h> | ||
24 | |||
25 | #include "sir-dev.h" | ||
26 | |||
27 | /************************************************************************** | ||
28 | * | ||
29 | * kIrDAd kernel thread and config state machine | ||
30 | * | ||
31 | */ | ||
32 | |||
33 | struct irda_request_queue { | ||
34 | struct list_head request_list; | ||
35 | spinlock_t lock; | ||
36 | task_t *thread; | ||
37 | struct completion exit; | ||
38 | wait_queue_head_t kick, done; | ||
39 | atomic_t num_pending; | ||
40 | }; | ||
41 | |||
42 | static struct irda_request_queue irda_rq_queue; | ||
43 | |||
44 | static int irda_queue_request(struct irda_request *rq) | ||
45 | { | ||
46 | int ret = 0; | ||
47 | unsigned long flags; | ||
48 | |||
49 | if (!test_and_set_bit(0, &rq->pending)) { | ||
50 | spin_lock_irqsave(&irda_rq_queue.lock, flags); | ||
51 | list_add_tail(&rq->lh_request, &irda_rq_queue.request_list); | ||
52 | wake_up(&irda_rq_queue.kick); | ||
53 | atomic_inc(&irda_rq_queue.num_pending); | ||
54 | spin_unlock_irqrestore(&irda_rq_queue.lock, flags); | ||
55 | ret = 1; | ||
56 | } | ||
57 | return ret; | ||
58 | } | ||
59 | |||
60 | static void irda_request_timer(unsigned long data) | ||
61 | { | ||
62 | struct irda_request *rq = (struct irda_request *)data; | ||
63 | unsigned long flags; | ||
64 | |||
65 | spin_lock_irqsave(&irda_rq_queue.lock, flags); | ||
66 | list_add_tail(&rq->lh_request, &irda_rq_queue.request_list); | ||
67 | wake_up(&irda_rq_queue.kick); | ||
68 | spin_unlock_irqrestore(&irda_rq_queue.lock, flags); | ||
69 | } | ||
70 | |||
71 | static int irda_queue_delayed_request(struct irda_request *rq, unsigned long delay) | ||
72 | { | ||
73 | int ret = 0; | ||
74 | struct timer_list *timer = &rq->timer; | ||
75 | |||
76 | if (!test_and_set_bit(0, &rq->pending)) { | ||
77 | timer->expires = jiffies + delay; | ||
78 | timer->function = irda_request_timer; | ||
79 | timer->data = (unsigned long)rq; | ||
80 | atomic_inc(&irda_rq_queue.num_pending); | ||
81 | add_timer(timer); | ||
82 | ret = 1; | ||
83 | } | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | static void run_irda_queue(void) | ||
88 | { | ||
89 | unsigned long flags; | ||
90 | struct list_head *entry, *tmp; | ||
91 | struct irda_request *rq; | ||
92 | |||
93 | spin_lock_irqsave(&irda_rq_queue.lock, flags); | ||
94 | list_for_each_safe(entry, tmp, &irda_rq_queue.request_list) { | ||
95 | rq = list_entry(entry, struct irda_request, lh_request); | ||
96 | list_del_init(entry); | ||
97 | spin_unlock_irqrestore(&irda_rq_queue.lock, flags); | ||
98 | |||
99 | clear_bit(0, &rq->pending); | ||
100 | rq->func(rq->data); | ||
101 | |||
102 | if (atomic_dec_and_test(&irda_rq_queue.num_pending)) | ||
103 | wake_up(&irda_rq_queue.done); | ||
104 | |||
105 | spin_lock_irqsave(&irda_rq_queue.lock, flags); | ||
106 | } | ||
107 | spin_unlock_irqrestore(&irda_rq_queue.lock, flags); | ||
108 | } | ||
109 | |||
110 | static int irda_thread(void *startup) | ||
111 | { | ||
112 | DECLARE_WAITQUEUE(wait, current); | ||
113 | |||
114 | daemonize("kIrDAd"); | ||
115 | |||
116 | irda_rq_queue.thread = current; | ||
117 | |||
118 | complete((struct completion *)startup); | ||
119 | |||
120 | while (irda_rq_queue.thread != NULL) { | ||
121 | |||
122 | /* We use TASK_INTERRUPTIBLE, rather than | ||
123 | * TASK_UNINTERRUPTIBLE. Andrew Morton made this | ||
124 | * change ; he told me that it is safe, because "signal | ||
125 | * blocking is now handled in daemonize()", he added | ||
126 | * that the problem is that "uninterruptible sleep | ||
127 | * contributes to load average", making user worry. | ||
128 | * Jean II */ | ||
129 | set_task_state(current, TASK_INTERRUPTIBLE); | ||
130 | add_wait_queue(&irda_rq_queue.kick, &wait); | ||
131 | if (list_empty(&irda_rq_queue.request_list)) | ||
132 | schedule(); | ||
133 | else | ||
134 | __set_task_state(current, TASK_RUNNING); | ||
135 | remove_wait_queue(&irda_rq_queue.kick, &wait); | ||
136 | |||
137 | /* make swsusp happy with our thread */ | ||
138 | try_to_freeze(); | ||
139 | |||
140 | run_irda_queue(); | ||
141 | } | ||
142 | |||
143 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,35) | ||
144 | reparent_to_init(); | ||
145 | #endif | ||
146 | complete_and_exit(&irda_rq_queue.exit, 0); | ||
147 | /* never reached */ | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | |||
152 | static void flush_irda_queue(void) | ||
153 | { | ||
154 | if (atomic_read(&irda_rq_queue.num_pending)) { | ||
155 | |||
156 | DECLARE_WAITQUEUE(wait, current); | ||
157 | |||
158 | if (!list_empty(&irda_rq_queue.request_list)) | ||
159 | run_irda_queue(); | ||
160 | |||
161 | set_task_state(current, TASK_UNINTERRUPTIBLE); | ||
162 | add_wait_queue(&irda_rq_queue.done, &wait); | ||
163 | if (atomic_read(&irda_rq_queue.num_pending)) | ||
164 | schedule(); | ||
165 | else | ||
166 | __set_task_state(current, TASK_RUNNING); | ||
167 | remove_wait_queue(&irda_rq_queue.done, &wait); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | /* substate handler of the config-fsm to handle the cases where we want | ||
172 | * to wait for transmit completion before changing the port configuration | ||
173 | */ | ||
174 | |||
175 | static int irda_tx_complete_fsm(struct sir_dev *dev) | ||
176 | { | ||
177 | struct sir_fsm *fsm = &dev->fsm; | ||
178 | unsigned next_state, delay; | ||
179 | unsigned bytes_left; | ||
180 | |||
181 | do { | ||
182 | next_state = fsm->substate; /* default: stay in current substate */ | ||
183 | delay = 0; | ||
184 | |||
185 | switch(fsm->substate) { | ||
186 | |||
187 | case SIRDEV_STATE_WAIT_XMIT: | ||
188 | if (dev->drv->chars_in_buffer) | ||
189 | bytes_left = dev->drv->chars_in_buffer(dev); | ||
190 | else | ||
191 | bytes_left = 0; | ||
192 | if (!bytes_left) { | ||
193 | next_state = SIRDEV_STATE_WAIT_UNTIL_SENT; | ||
194 | break; | ||
195 | } | ||
196 | |||
197 | if (dev->speed > 115200) | ||
198 | delay = (bytes_left*8*10000) / (dev->speed/100); | ||
199 | else if (dev->speed > 0) | ||
200 | delay = (bytes_left*10*10000) / (dev->speed/100); | ||
201 | else | ||
202 | delay = 0; | ||
203 | /* expected delay (usec) until remaining bytes are sent */ | ||
204 | if (delay < 100) { | ||
205 | udelay(delay); | ||
206 | delay = 0; | ||
207 | break; | ||
208 | } | ||
209 | /* sleep some longer delay (msec) */ | ||
210 | delay = (delay+999) / 1000; | ||
211 | break; | ||
212 | |||
213 | case SIRDEV_STATE_WAIT_UNTIL_SENT: | ||
214 | /* block until underlaying hardware buffer are empty */ | ||
215 | if (dev->drv->wait_until_sent) | ||
216 | dev->drv->wait_until_sent(dev); | ||
217 | next_state = SIRDEV_STATE_TX_DONE; | ||
218 | break; | ||
219 | |||
220 | case SIRDEV_STATE_TX_DONE: | ||
221 | return 0; | ||
222 | |||
223 | default: | ||
224 | IRDA_ERROR("%s - undefined state\n", __FUNCTION__); | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | fsm->substate = next_state; | ||
228 | } while (delay == 0); | ||
229 | return delay; | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * Function irda_config_fsm | ||
234 | * | ||
235 | * State machine to handle the configuration of the device (and attached dongle, if any). | ||
236 | * This handler is scheduled for execution in kIrDAd context, so we can sleep. | ||
237 | * however, kIrDAd is shared by all sir_dev devices so we better don't sleep there too | ||
238 | * long. Instead, for longer delays we start a timer to reschedule us later. | ||
239 | * On entry, fsm->sem is always locked and the netdev xmit queue stopped. | ||
240 | * Both must be unlocked/restarted on completion - but only on final exit. | ||
241 | */ | ||
242 | |||
243 | static void irda_config_fsm(void *data) | ||
244 | { | ||
245 | struct sir_dev *dev = data; | ||
246 | struct sir_fsm *fsm = &dev->fsm; | ||
247 | int next_state; | ||
248 | int ret = -1; | ||
249 | unsigned delay; | ||
250 | |||
251 | IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); | ||
252 | |||
253 | do { | ||
254 | IRDA_DEBUG(3, "%s - state=0x%04x / substate=0x%04x\n", | ||
255 | __FUNCTION__, fsm->state, fsm->substate); | ||
256 | |||
257 | next_state = fsm->state; | ||
258 | delay = 0; | ||
259 | |||
260 | switch(fsm->state) { | ||
261 | |||
262 | case SIRDEV_STATE_DONGLE_OPEN: | ||
263 | if (dev->dongle_drv != NULL) { | ||
264 | ret = sirdev_put_dongle(dev); | ||
265 | if (ret) { | ||
266 | fsm->result = -EINVAL; | ||
267 | next_state = SIRDEV_STATE_ERROR; | ||
268 | break; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | /* Initialize dongle */ | ||
273 | ret = sirdev_get_dongle(dev, fsm->param); | ||
274 | if (ret) { | ||
275 | fsm->result = ret; | ||
276 | next_state = SIRDEV_STATE_ERROR; | ||
277 | break; | ||
278 | } | ||
279 | |||
280 | /* Dongles are powered through the modem control lines which | ||
281 | * were just set during open. Before resetting, let's wait for | ||
282 | * the power to stabilize. This is what some dongle drivers did | ||
283 | * in open before, while others didn't - should be safe anyway. | ||
284 | */ | ||
285 | |||
286 | delay = 50; | ||
287 | fsm->substate = SIRDEV_STATE_DONGLE_RESET; | ||
288 | next_state = SIRDEV_STATE_DONGLE_RESET; | ||
289 | |||
290 | fsm->param = 9600; | ||
291 | |||
292 | break; | ||
293 | |||
294 | case SIRDEV_STATE_DONGLE_CLOSE: | ||
295 | /* shouldn't we just treat this as success=? */ | ||
296 | if (dev->dongle_drv == NULL) { | ||
297 | fsm->result = -EINVAL; | ||
298 | next_state = SIRDEV_STATE_ERROR; | ||
299 | break; | ||
300 | } | ||
301 | |||
302 | ret = sirdev_put_dongle(dev); | ||
303 | if (ret) { | ||
304 | fsm->result = ret; | ||
305 | next_state = SIRDEV_STATE_ERROR; | ||
306 | break; | ||
307 | } | ||
308 | next_state = SIRDEV_STATE_DONE; | ||
309 | break; | ||
310 | |||
311 | case SIRDEV_STATE_SET_DTR_RTS: | ||
312 | ret = sirdev_set_dtr_rts(dev, | ||
313 | (fsm->param&0x02) ? TRUE : FALSE, | ||
314 | (fsm->param&0x01) ? TRUE : FALSE); | ||
315 | next_state = SIRDEV_STATE_DONE; | ||
316 | break; | ||
317 | |||
318 | case SIRDEV_STATE_SET_SPEED: | ||
319 | fsm->substate = SIRDEV_STATE_WAIT_XMIT; | ||
320 | next_state = SIRDEV_STATE_DONGLE_CHECK; | ||
321 | break; | ||
322 | |||
323 | case SIRDEV_STATE_DONGLE_CHECK: | ||
324 | ret = irda_tx_complete_fsm(dev); | ||
325 | if (ret < 0) { | ||
326 | fsm->result = ret; | ||
327 | next_state = SIRDEV_STATE_ERROR; | ||
328 | break; | ||
329 | } | ||
330 | if ((delay=ret) != 0) | ||
331 | break; | ||
332 | |||
333 | if (dev->dongle_drv) { | ||
334 | fsm->substate = SIRDEV_STATE_DONGLE_RESET; | ||
335 | next_state = SIRDEV_STATE_DONGLE_RESET; | ||
336 | } | ||
337 | else { | ||
338 | dev->speed = fsm->param; | ||
339 | next_state = SIRDEV_STATE_PORT_SPEED; | ||
340 | } | ||
341 | break; | ||
342 | |||
343 | case SIRDEV_STATE_DONGLE_RESET: | ||
344 | if (dev->dongle_drv->reset) { | ||
345 | ret = dev->dongle_drv->reset(dev); | ||
346 | if (ret < 0) { | ||
347 | fsm->result = ret; | ||
348 | next_state = SIRDEV_STATE_ERROR; | ||
349 | break; | ||
350 | } | ||
351 | } | ||
352 | else | ||
353 | ret = 0; | ||
354 | if ((delay=ret) == 0) { | ||
355 | /* set serial port according to dongle default speed */ | ||
356 | if (dev->drv->set_speed) | ||
357 | dev->drv->set_speed(dev, dev->speed); | ||
358 | fsm->substate = SIRDEV_STATE_DONGLE_SPEED; | ||
359 | next_state = SIRDEV_STATE_DONGLE_SPEED; | ||
360 | } | ||
361 | break; | ||
362 | |||
363 | case SIRDEV_STATE_DONGLE_SPEED: | ||
364 | if (dev->dongle_drv->reset) { | ||
365 | ret = dev->dongle_drv->set_speed(dev, fsm->param); | ||
366 | if (ret < 0) { | ||
367 | fsm->result = ret; | ||
368 | next_state = SIRDEV_STATE_ERROR; | ||
369 | break; | ||
370 | } | ||
371 | } | ||
372 | else | ||
373 | ret = 0; | ||
374 | if ((delay=ret) == 0) | ||
375 | next_state = SIRDEV_STATE_PORT_SPEED; | ||
376 | break; | ||
377 | |||
378 | case SIRDEV_STATE_PORT_SPEED: | ||
379 | /* Finally we are ready to change the serial port speed */ | ||
380 | if (dev->drv->set_speed) | ||
381 | dev->drv->set_speed(dev, dev->speed); | ||
382 | dev->new_speed = 0; | ||
383 | next_state = SIRDEV_STATE_DONE; | ||
384 | break; | ||
385 | |||
386 | case SIRDEV_STATE_DONE: | ||
387 | /* Signal network layer so it can send more frames */ | ||
388 | netif_wake_queue(dev->netdev); | ||
389 | next_state = SIRDEV_STATE_COMPLETE; | ||
390 | break; | ||
391 | |||
392 | default: | ||
393 | IRDA_ERROR("%s - undefined state\n", __FUNCTION__); | ||
394 | fsm->result = -EINVAL; | ||
395 | /* fall thru */ | ||
396 | |||
397 | case SIRDEV_STATE_ERROR: | ||
398 | IRDA_ERROR("%s - error: %d\n", __FUNCTION__, fsm->result); | ||
399 | |||
400 | #if 0 /* don't enable this before we have netdev->tx_timeout to recover */ | ||
401 | netif_stop_queue(dev->netdev); | ||
402 | #else | ||
403 | netif_wake_queue(dev->netdev); | ||
404 | #endif | ||
405 | /* fall thru */ | ||
406 | |||
407 | case SIRDEV_STATE_COMPLETE: | ||
408 | /* config change finished, so we are not busy any longer */ | ||
409 | sirdev_enable_rx(dev); | ||
410 | up(&fsm->sem); | ||
411 | return; | ||
412 | } | ||
413 | fsm->state = next_state; | ||
414 | } while(!delay); | ||
415 | |||
416 | irda_queue_delayed_request(&fsm->rq, msecs_to_jiffies(delay)); | ||
417 | } | ||
418 | |||
419 | /* schedule some device configuration task for execution by kIrDAd | ||
420 | * on behalf of the above state machine. | ||
421 | * can be called from process or interrupt/tasklet context. | ||
422 | */ | ||
423 | |||
424 | int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned param) | ||
425 | { | ||
426 | struct sir_fsm *fsm = &dev->fsm; | ||
427 | int xmit_was_down; | ||
428 | |||
429 | IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param); | ||
430 | |||
431 | if (down_trylock(&fsm->sem)) { | ||
432 | if (in_interrupt() || in_atomic() || irqs_disabled()) { | ||
433 | IRDA_DEBUG(1, "%s(), state machine busy!\n", __FUNCTION__); | ||
434 | return -EWOULDBLOCK; | ||
435 | } else | ||
436 | down(&fsm->sem); | ||
437 | } | ||
438 | |||
439 | if (fsm->state == SIRDEV_STATE_DEAD) { | ||
440 | /* race with sirdev_close should never happen */ | ||
441 | IRDA_ERROR("%s(), instance staled!\n", __FUNCTION__); | ||
442 | up(&fsm->sem); | ||
443 | return -ESTALE; /* or better EPIPE? */ | ||
444 | } | ||
445 | |||
446 | xmit_was_down = netif_queue_stopped(dev->netdev); | ||
447 | netif_stop_queue(dev->netdev); | ||
448 | atomic_set(&dev->enable_rx, 0); | ||
449 | |||
450 | fsm->state = initial_state; | ||
451 | fsm->param = param; | ||
452 | fsm->result = 0; | ||
453 | |||
454 | INIT_LIST_HEAD(&fsm->rq.lh_request); | ||
455 | fsm->rq.pending = 0; | ||
456 | fsm->rq.func = irda_config_fsm; | ||
457 | fsm->rq.data = dev; | ||
458 | |||
459 | if (!irda_queue_request(&fsm->rq)) { /* returns 0 on error! */ | ||
460 | atomic_set(&dev->enable_rx, 1); | ||
461 | if (!xmit_was_down) | ||
462 | netif_wake_queue(dev->netdev); | ||
463 | up(&fsm->sem); | ||
464 | return -EAGAIN; | ||
465 | } | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static int __init irda_thread_create(void) | ||
470 | { | ||
471 | struct completion startup; | ||
472 | int pid; | ||
473 | |||
474 | spin_lock_init(&irda_rq_queue.lock); | ||
475 | irda_rq_queue.thread = NULL; | ||
476 | INIT_LIST_HEAD(&irda_rq_queue.request_list); | ||
477 | init_waitqueue_head(&irda_rq_queue.kick); | ||
478 | init_waitqueue_head(&irda_rq_queue.done); | ||
479 | atomic_set(&irda_rq_queue.num_pending, 0); | ||
480 | |||
481 | init_completion(&startup); | ||
482 | pid = kernel_thread(irda_thread, &startup, CLONE_FS|CLONE_FILES); | ||
483 | if (pid <= 0) | ||
484 | return -EAGAIN; | ||
485 | else | ||
486 | wait_for_completion(&startup); | ||
487 | |||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static void __exit irda_thread_join(void) | ||
492 | { | ||
493 | if (irda_rq_queue.thread) { | ||
494 | flush_irda_queue(); | ||
495 | init_completion(&irda_rq_queue.exit); | ||
496 | irda_rq_queue.thread = NULL; | ||
497 | wake_up(&irda_rq_queue.kick); | ||
498 | wait_for_completion(&irda_rq_queue.exit); | ||
499 | } | ||
500 | } | ||
501 | |||
502 | module_init(irda_thread_create); | ||
503 | module_exit(irda_thread_join); | ||
504 | |||
505 | MODULE_AUTHOR("Martin Diehl <info@mdiehl.de>"); | ||
506 | MODULE_DESCRIPTION("IrDA SIR core"); | ||
507 | MODULE_LICENSE("GPL"); | ||
508 | |||
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index bbcfc8ec35a1..a4674044bd6f 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include <linux/rtnetlink.h> | 54 | #include <linux/rtnetlink.h> |
55 | #include <linux/serial_reg.h> | 55 | #include <linux/serial_reg.h> |
56 | #include <linux/dma-mapping.h> | 56 | #include <linux/dma-mapping.h> |
57 | #include <linux/pnp.h> | ||
57 | #include <linux/platform_device.h> | 58 | #include <linux/platform_device.h> |
58 | 59 | ||
59 | #include <asm/io.h> | 60 | #include <asm/io.h> |
@@ -225,6 +226,8 @@ static int __init smsc_superio_lpc(unsigned short cfg_base); | |||
225 | #ifdef CONFIG_PCI | 226 | #ifdef CONFIG_PCI |
226 | static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); | 227 | static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); |
227 | static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); | 228 | static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); |
229 | static void __init preconfigure_ali_port(struct pci_dev *dev, | ||
230 | unsigned short port); | ||
228 | static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); | 231 | static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); |
229 | static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, | 232 | static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, |
230 | unsigned short ircc_fir, | 233 | unsigned short ircc_fir, |
@@ -356,6 +359,16 @@ static inline void register_bank(int iobase, int bank) | |||
356 | iobase + IRCC_MASTER); | 359 | iobase + IRCC_MASTER); |
357 | } | 360 | } |
358 | 361 | ||
362 | #ifdef CONFIG_PNP | ||
363 | /* PNP hotplug support */ | ||
364 | static const struct pnp_device_id smsc_ircc_pnp_table[] = { | ||
365 | { .id = "SMCf010", .driver_data = 0 }, | ||
366 | /* and presumably others */ | ||
367 | { } | ||
368 | }; | ||
369 | MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table); | ||
370 | #endif | ||
371 | |||
359 | 372 | ||
360 | /******************************************************************************* | 373 | /******************************************************************************* |
361 | * | 374 | * |
@@ -2070,7 +2083,8 @@ static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self) | |||
2070 | 2083 | ||
2071 | /* PROBING | 2084 | /* PROBING |
2072 | * | 2085 | * |
2073 | * | 2086 | * REVISIT we can be told about the device by PNP, and should use that info |
2087 | * instead of probing hardware and creating a platform_device ... | ||
2074 | */ | 2088 | */ |
2075 | 2089 | ||
2076 | static int __init smsc_ircc_look_for_chips(void) | 2090 | static int __init smsc_ircc_look_for_chips(void) |
@@ -2327,9 +2341,14 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) | |||
2327 | * pre-configuration not properly done by the BIOS (especially laptops) | 2341 | * pre-configuration not properly done by the BIOS (especially laptops) |
2328 | * This code is based in part on smcinit.c, tosh1800-smcinit.c | 2342 | * This code is based in part on smcinit.c, tosh1800-smcinit.c |
2329 | * and tosh2450-smcinit.c. The table lists the device entries | 2343 | * and tosh2450-smcinit.c. The table lists the device entries |
2330 | * for ISA bridges with an LPC (Local Peripheral Configurator) | 2344 | * for ISA bridges with an LPC (Low Pin Count) controller which |
2331 | * that are in turn used to configure the SMSC device with default | 2345 | * handles the communication with the SMSC device. After the LPC |
2332 | * SIR and FIR I/O ports, DMA and IRQ. | 2346 | * controller is initialized through PCI, the SMSC device is initialized |
2347 | * through a dedicated port in the ISA port-mapped I/O area, this latter | ||
2348 | * area is used to configure the SMSC device with default | ||
2349 | * SIR and FIR I/O ports, DMA and IRQ. Different vendors have | ||
2350 | * used different sets of parameters and different control port | ||
2351 | * addresses making a subsystem device table necessary. | ||
2333 | */ | 2352 | */ |
2334 | #ifdef CONFIG_PCI | 2353 | #ifdef CONFIG_PCI |
2335 | #define PCIID_VENDOR_INTEL 0x8086 | 2354 | #define PCIID_VENDOR_INTEL 0x8086 |
@@ -2340,9 +2359,10 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __dev | |||
2340 | .device = 0x24cc, | 2359 | .device = 0x24cc, |
2341 | .subvendor = 0x103c, | 2360 | .subvendor = 0x103c, |
2342 | .subdevice = 0x088c, | 2361 | .subdevice = 0x088c, |
2343 | .sir_io = 0x02f8, /* Quite certain these are the same for nc8000 as for nc6000 */ | 2362 | /* Quite certain these are the same for nc8000 as for nc6000 */ |
2363 | .sir_io = 0x02f8, | ||
2344 | .fir_io = 0x0130, | 2364 | .fir_io = 0x0130, |
2345 | .fir_irq = 0x09, | 2365 | .fir_irq = 0x05, |
2346 | .fir_dma = 0x03, | 2366 | .fir_dma = 0x03, |
2347 | .cfg_base = 0x004e, | 2367 | .cfg_base = 0x004e, |
2348 | .preconfigure = preconfigure_through_82801, | 2368 | .preconfigure = preconfigure_through_82801, |
@@ -2355,60 +2375,79 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __dev | |||
2355 | .subdevice = 0x0890, | 2375 | .subdevice = 0x0890, |
2356 | .sir_io = 0x02f8, | 2376 | .sir_io = 0x02f8, |
2357 | .fir_io = 0x0130, | 2377 | .fir_io = 0x0130, |
2358 | .fir_irq = 0x09, | 2378 | .fir_irq = 0x05, |
2359 | .fir_dma = 0x03, | 2379 | .fir_dma = 0x03, |
2360 | .cfg_base = 0x004e, | 2380 | .cfg_base = 0x004e, |
2361 | .preconfigure = preconfigure_through_82801, | 2381 | .preconfigure = preconfigure_through_82801, |
2362 | .name = "HP nc6000", | 2382 | .name = "HP nc6000", |
2363 | }, | 2383 | }, |
2364 | { | 2384 | { |
2365 | .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ | 2385 | /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ |
2386 | .vendor = PCIID_VENDOR_INTEL, | ||
2366 | .device = 0x24c0, | 2387 | .device = 0x24c0, |
2367 | .subvendor = 0x1179, | 2388 | .subvendor = 0x1179, |
2368 | .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ | 2389 | .subdevice = 0xffff, /* 0xffff is "any" */ |
2369 | .sir_io = 0x03f8, | 2390 | .sir_io = 0x03f8, |
2370 | .fir_io = 0x0130, | 2391 | .fir_io = 0x0130, |
2371 | .fir_irq = 0x07, | 2392 | .fir_irq = 0x07, |
2372 | .fir_dma = 0x01, | 2393 | .fir_dma = 0x01, |
2373 | .cfg_base = 0x002e, | 2394 | .cfg_base = 0x002e, |
2374 | .preconfigure = preconfigure_through_82801, | 2395 | .preconfigure = preconfigure_through_82801, |
2375 | .name = "Toshiba Satellite 2450", | 2396 | .name = "Toshiba laptop with Intel 82801DB/DBL LPC bridge", |
2376 | }, | 2397 | }, |
2377 | { | 2398 | { |
2378 | .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */ | 2399 | .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */ |
2379 | .device = 0x248c, /* Some use 24cc? */ | 2400 | .device = 0x248c, |
2401 | .subvendor = 0x1179, | ||
2402 | .subdevice = 0xffff, /* 0xffff is "any" */ | ||
2403 | .sir_io = 0x03f8, | ||
2404 | .fir_io = 0x0130, | ||
2405 | .fir_irq = 0x03, | ||
2406 | .fir_dma = 0x03, | ||
2407 | .cfg_base = 0x002e, | ||
2408 | .preconfigure = preconfigure_through_82801, | ||
2409 | .name = "Toshiba laptop with Intel 82801CAM ISA bridge", | ||
2410 | }, | ||
2411 | { | ||
2412 | /* 82801DBM (ICH4-M) LPC Interface Bridge */ | ||
2413 | .vendor = PCIID_VENDOR_INTEL, | ||
2414 | .device = 0x24cc, | ||
2380 | .subvendor = 0x1179, | 2415 | .subvendor = 0x1179, |
2381 | .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ | 2416 | .subdevice = 0xffff, /* 0xffff is "any" */ |
2382 | .sir_io = 0x03f8, | 2417 | .sir_io = 0x03f8, |
2383 | .fir_io = 0x0130, | 2418 | .fir_io = 0x0130, |
2384 | .fir_irq = 0x03, | 2419 | .fir_irq = 0x03, |
2385 | .fir_dma = 0x03, | 2420 | .fir_dma = 0x03, |
2386 | .cfg_base = 0x002e, | 2421 | .cfg_base = 0x002e, |
2387 | .preconfigure = preconfigure_through_82801, | 2422 | .preconfigure = preconfigure_through_82801, |
2388 | .name = "Toshiba Satellite 5100/5200, Tecra 9100", | 2423 | .name = "Toshiba laptop with Intel 8281DBM LPC bridge", |
2389 | }, | 2424 | }, |
2390 | { | 2425 | { |
2391 | .vendor = PCIID_VENDOR_ALI, /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ | 2426 | /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ |
2427 | .vendor = PCIID_VENDOR_ALI, | ||
2392 | .device = 0x1533, | 2428 | .device = 0x1533, |
2393 | .subvendor = 0x1179, | 2429 | .subvendor = 0x1179, |
2394 | .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ | 2430 | .subdevice = 0xffff, /* 0xffff is "any" */ |
2395 | .sir_io = 0x02e8, | 2431 | .sir_io = 0x02e8, |
2396 | .fir_io = 0x02f8, | 2432 | .fir_io = 0x02f8, |
2397 | .fir_irq = 0x07, | 2433 | .fir_irq = 0x07, |
2398 | .fir_dma = 0x03, | 2434 | .fir_dma = 0x03, |
2399 | .cfg_base = 0x002e, | 2435 | .cfg_base = 0x002e, |
2400 | .preconfigure = preconfigure_through_ali, | 2436 | .preconfigure = preconfigure_through_ali, |
2401 | .name = "Toshiba Satellite 1800", | 2437 | .name = "Toshiba laptop with ALi ISA bridge", |
2402 | }, | 2438 | }, |
2403 | { } // Terminator | 2439 | { } // Terminator |
2404 | }; | 2440 | }; |
2405 | 2441 | ||
2406 | 2442 | ||
2407 | /* | 2443 | /* |
2408 | * This sets up the basic SMSC parameters (FIR port, SIR port, FIR DMA, FIR IRQ) | 2444 | * This sets up the basic SMSC parameters |
2445 | * (FIR port, SIR port, FIR DMA, FIR IRQ) | ||
2409 | * through the chip configuration port. | 2446 | * through the chip configuration port. |
2410 | */ | 2447 | */ |
2411 | static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf) | 2448 | static int __init preconfigure_smsc_chip(struct |
2449 | smsc_ircc_subsystem_configuration | ||
2450 | *conf) | ||
2412 | { | 2451 | { |
2413 | unsigned short iobase = conf->cfg_base; | 2452 | unsigned short iobase = conf->cfg_base; |
2414 | unsigned char tmpbyte; | 2453 | unsigned char tmpbyte; |
@@ -2416,7 +2455,9 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio | |||
2416 | outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state | 2455 | outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state |
2417 | outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID | 2456 | outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID |
2418 | tmpbyte = inb(iobase +1); // Read device ID | 2457 | tmpbyte = inb(iobase +1); // Read device ID |
2419 | IRDA_DEBUG(0, "Detected Chip id: 0x%02x, setting up registers...\n",tmpbyte); | 2458 | IRDA_DEBUG(0, |
2459 | "Detected Chip id: 0x%02x, setting up registers...\n", | ||
2460 | tmpbyte); | ||
2420 | 2461 | ||
2421 | /* Disable UART1 and set up SIR I/O port */ | 2462 | /* Disable UART1 and set up SIR I/O port */ |
2422 | outb(0x24, iobase); // select CR24 - UART1 base addr | 2463 | outb(0x24, iobase); // select CR24 - UART1 base addr |
@@ -2426,6 +2467,7 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio | |||
2426 | tmpbyte = inb(iobase + 1); | 2467 | tmpbyte = inb(iobase + 1); |
2427 | if (tmpbyte != (conf->sir_io >> 2) ) { | 2468 | if (tmpbyte != (conf->sir_io >> 2) ) { |
2428 | IRDA_WARNING("ERROR: could not configure SIR ioport.\n"); | 2469 | IRDA_WARNING("ERROR: could not configure SIR ioport.\n"); |
2470 | IRDA_WARNING("Try to supply ircc_cfg argument.\n"); | ||
2429 | return -ENXIO; | 2471 | return -ENXIO; |
2430 | } | 2472 | } |
2431 | 2473 | ||
@@ -2461,7 +2503,8 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio | |||
2461 | 2503 | ||
2462 | outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode | 2504 | outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode |
2463 | tmpbyte = inb(iobase + 1); | 2505 | tmpbyte = inb(iobase + 1); |
2464 | tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | SMSCSIOFLAT_UART2MODE_VAL_IRDA; | 2506 | tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | |
2507 | SMSCSIOFLAT_UART2MODE_VAL_IRDA; | ||
2465 | outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed | 2508 | outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed |
2466 | 2509 | ||
2467 | outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel | 2510 | outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel |
@@ -2486,53 +2529,226 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio | |||
2486 | return 0; | 2529 | return 0; |
2487 | } | 2530 | } |
2488 | 2531 | ||
2489 | /* 82801CAM registers */ | 2532 | /* 82801CAM generic registers */ |
2490 | #define VID 0x00 | 2533 | #define VID 0x00 |
2491 | #define DID 0x02 | 2534 | #define DID 0x02 |
2492 | #define PIRQA_ROUT 0x60 | 2535 | #define PIRQ_A_D_ROUT 0x60 |
2536 | #define SIRQ_CNTL 0x64 | ||
2537 | #define PIRQ_E_H_ROUT 0x68 | ||
2493 | #define PCI_DMA_C 0x90 | 2538 | #define PCI_DMA_C 0x90 |
2539 | /* LPC-specific registers */ | ||
2494 | #define COM_DEC 0xe0 | 2540 | #define COM_DEC 0xe0 |
2541 | #define GEN1_DEC 0xe4 | ||
2495 | #define LPC_EN 0xe6 | 2542 | #define LPC_EN 0xe6 |
2496 | #define GEN2_DEC 0xec | 2543 | #define GEN2_DEC 0xec |
2497 | /* | 2544 | /* |
2498 | * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge or | 2545 | * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge |
2499 | * Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. They all work the same way! | 2546 | * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. |
2547 | * They all work the same way! | ||
2500 | */ | 2548 | */ |
2501 | static int __init preconfigure_through_82801(struct pci_dev *dev, | 2549 | static int __init preconfigure_through_82801(struct pci_dev *dev, |
2502 | struct smsc_ircc_subsystem_configuration *conf) | 2550 | struct |
2551 | smsc_ircc_subsystem_configuration | ||
2552 | *conf) | ||
2503 | { | 2553 | { |
2504 | unsigned short tmpword; | 2554 | unsigned short tmpword; |
2505 | int ret; | 2555 | unsigned char tmpbyte; |
2506 | 2556 | ||
2507 | IRDA_MESSAGE("Setting up the SMSC device via the 82801 controller.\n"); | 2557 | IRDA_MESSAGE("Setting up Intel 82801 controller and SMSC device\n"); |
2508 | pci_write_config_byte(dev, COM_DEC, 0x10); | 2558 | /* |
2559 | * Select the range for the COMA COM port (SIR) | ||
2560 | * Register COM_DEC: | ||
2561 | * Bit 7: reserved | ||
2562 | * Bit 6-4, COMB decode range | ||
2563 | * Bit 3: reserved | ||
2564 | * Bit 2-0, COMA decode range | ||
2565 | * | ||
2566 | * Decode ranges: | ||
2567 | * 000 = 0x3f8-0x3ff (COM1) | ||
2568 | * 001 = 0x2f8-0x2ff (COM2) | ||
2569 | * 010 = 0x220-0x227 | ||
2570 | * 011 = 0x228-0x22f | ||
2571 | * 100 = 0x238-0x23f | ||
2572 | * 101 = 0x2e8-0x2ef (COM4) | ||
2573 | * 110 = 0x338-0x33f | ||
2574 | * 111 = 0x3e8-0x3ef (COM3) | ||
2575 | */ | ||
2576 | pci_read_config_byte(dev, COM_DEC, &tmpbyte); | ||
2577 | tmpbyte &= 0xf8; /* mask COMA bits */ | ||
2578 | switch(conf->sir_io) { | ||
2579 | case 0x3f8: | ||
2580 | tmpbyte |= 0x00; | ||
2581 | break; | ||
2582 | case 0x2f8: | ||
2583 | tmpbyte |= 0x01; | ||
2584 | break; | ||
2585 | case 0x220: | ||
2586 | tmpbyte |= 0x02; | ||
2587 | break; | ||
2588 | case 0x228: | ||
2589 | tmpbyte |= 0x03; | ||
2590 | break; | ||
2591 | case 0x238: | ||
2592 | tmpbyte |= 0x04; | ||
2593 | break; | ||
2594 | case 0x2e8: | ||
2595 | tmpbyte |= 0x05; | ||
2596 | break; | ||
2597 | case 0x338: | ||
2598 | tmpbyte |= 0x06; | ||
2599 | break; | ||
2600 | case 0x3e8: | ||
2601 | tmpbyte |= 0x07; | ||
2602 | break; | ||
2603 | default: | ||
2604 | tmpbyte |= 0x01; /* COM2 default */ | ||
2605 | } | ||
2606 | IRDA_DEBUG(1, "COM_DEC (write): 0x%02x\n", tmpbyte); | ||
2607 | pci_write_config_byte(dev, COM_DEC, tmpbyte); | ||
2509 | 2608 | ||
2510 | /* Enable LPC */ | 2609 | /* Enable Low Pin Count interface */ |
2511 | pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ | 2610 | pci_read_config_word(dev, LPC_EN, &tmpword); |
2512 | tmpword &= 0xfffd; /* mask bit 1 */ | 2611 | /* These seem to be set up at all times, |
2513 | tmpword |= 0x0001; /* set bit 0 : COMA addr range enable */ | 2612 | * just make sure it is properly set. |
2613 | */ | ||
2614 | switch(conf->cfg_base) { | ||
2615 | case 0x04e: | ||
2616 | tmpword |= 0x2000; | ||
2617 | break; | ||
2618 | case 0x02e: | ||
2619 | tmpword |= 0x1000; | ||
2620 | break; | ||
2621 | case 0x062: | ||
2622 | tmpword |= 0x0800; | ||
2623 | break; | ||
2624 | case 0x060: | ||
2625 | tmpword |= 0x0400; | ||
2626 | break; | ||
2627 | default: | ||
2628 | IRDA_WARNING("Uncommon I/O base address: 0x%04x\n", | ||
2629 | conf->cfg_base); | ||
2630 | break; | ||
2631 | } | ||
2632 | tmpword &= 0xfffd; /* disable LPC COMB */ | ||
2633 | tmpword |= 0x0001; /* set bit 0 : enable LPC COMA addr range (GEN2) */ | ||
2634 | IRDA_DEBUG(1, "LPC_EN (write): 0x%04x\n", tmpword); | ||
2514 | pci_write_config_word(dev, LPC_EN, tmpword); | 2635 | pci_write_config_word(dev, LPC_EN, tmpword); |
2515 | 2636 | ||
2516 | /* Setup DMA */ | 2637 | /* |
2517 | pci_write_config_word(dev, PCI_DMA_C, 0xc0c0); /* LPC I/F DMA on, channel 3 -- rtm (?? PCI DMA ?) */ | 2638 | * Configure LPC DMA channel |
2518 | pci_write_config_word(dev, GEN2_DEC, 0x131); /* LPC I/F 2nd decode range */ | 2639 | * PCI_DMA_C bits: |
2640 | * Bit 15-14: DMA channel 7 select | ||
2641 | * Bit 13-12: DMA channel 6 select | ||
2642 | * Bit 11-10: DMA channel 5 select | ||
2643 | * Bit 9-8: Reserved | ||
2644 | * Bit 7-6: DMA channel 3 select | ||
2645 | * Bit 5-4: DMA channel 2 select | ||
2646 | * Bit 3-2: DMA channel 1 select | ||
2647 | * Bit 1-0: DMA channel 0 select | ||
2648 | * 00 = Reserved value | ||
2649 | * 01 = PC/PCI DMA | ||
2650 | * 10 = Reserved value | ||
2651 | * 11 = LPC I/F DMA | ||
2652 | */ | ||
2653 | pci_read_config_word(dev, PCI_DMA_C, &tmpword); | ||
2654 | switch(conf->fir_dma) { | ||
2655 | case 0x07: | ||
2656 | tmpword |= 0xc000; | ||
2657 | break; | ||
2658 | case 0x06: | ||
2659 | tmpword |= 0x3000; | ||
2660 | break; | ||
2661 | case 0x05: | ||
2662 | tmpword |= 0x0c00; | ||
2663 | break; | ||
2664 | case 0x03: | ||
2665 | tmpword |= 0x00c0; | ||
2666 | break; | ||
2667 | case 0x02: | ||
2668 | tmpword |= 0x0030; | ||
2669 | break; | ||
2670 | case 0x01: | ||
2671 | tmpword |= 0x000c; | ||
2672 | break; | ||
2673 | case 0x00: | ||
2674 | tmpword |= 0x0003; | ||
2675 | break; | ||
2676 | default: | ||
2677 | break; /* do not change settings */ | ||
2678 | } | ||
2679 | IRDA_DEBUG(1, "PCI_DMA_C (write): 0x%04x\n", tmpword); | ||
2680 | pci_write_config_word(dev, PCI_DMA_C, tmpword); | ||
2681 | |||
2682 | /* | ||
2683 | * GEN2_DEC bits: | ||
2684 | * Bit 15-4: Generic I/O range | ||
2685 | * Bit 3-1: reserved (read as 0) | ||
2686 | * Bit 0: enable GEN2 range on LPC I/F | ||
2687 | */ | ||
2688 | tmpword = conf->fir_io & 0xfff8; | ||
2689 | tmpword |= 0x0001; | ||
2690 | IRDA_DEBUG(1, "GEN2_DEC (write): 0x%04x\n", tmpword); | ||
2691 | pci_write_config_word(dev, GEN2_DEC, tmpword); | ||
2519 | 2692 | ||
2520 | /* Pre-configure chip */ | 2693 | /* Pre-configure chip */ |
2521 | ret = preconfigure_smsc_chip(conf); | 2694 | return preconfigure_smsc_chip(conf); |
2695 | } | ||
2522 | 2696 | ||
2523 | /* Disable LPC */ | 2697 | /* |
2524 | pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ | 2698 | * Pre-configure a certain port on the ALi 1533 bridge. |
2525 | tmpword &= 0xfffc; /* mask bit 1 and bit 0, COMA addr range disable */ | 2699 | * This is based on reverse-engineering since ALi does not |
2526 | pci_write_config_word(dev, LPC_EN, tmpword); | 2700 | * provide any data sheet for the 1533 chip. |
2527 | return ret; | 2701 | */ |
2702 | static void __init preconfigure_ali_port(struct pci_dev *dev, | ||
2703 | unsigned short port) | ||
2704 | { | ||
2705 | unsigned char reg; | ||
2706 | /* These bits obviously control the different ports */ | ||
2707 | unsigned char mask; | ||
2708 | unsigned char tmpbyte; | ||
2709 | |||
2710 | switch(port) { | ||
2711 | case 0x0130: | ||
2712 | case 0x0178: | ||
2713 | reg = 0xb0; | ||
2714 | mask = 0x80; | ||
2715 | break; | ||
2716 | case 0x03f8: | ||
2717 | reg = 0xb4; | ||
2718 | mask = 0x80; | ||
2719 | break; | ||
2720 | case 0x02f8: | ||
2721 | reg = 0xb4; | ||
2722 | mask = 0x30; | ||
2723 | break; | ||
2724 | case 0x02e8: | ||
2725 | reg = 0xb4; | ||
2726 | mask = 0x08; | ||
2727 | break; | ||
2728 | default: | ||
2729 | IRDA_ERROR("Failed to configure unsupported port on ALi 1533 bridge: 0x%04x\n", port); | ||
2730 | return; | ||
2731 | } | ||
2732 | |||
2733 | pci_read_config_byte(dev, reg, &tmpbyte); | ||
2734 | /* Turn on the right bits */ | ||
2735 | tmpbyte |= mask; | ||
2736 | pci_write_config_byte(dev, reg, tmpbyte); | ||
2737 | IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port); | ||
2738 | return; | ||
2528 | } | 2739 | } |
2529 | 2740 | ||
2530 | static int __init preconfigure_through_ali(struct pci_dev *dev, | 2741 | static int __init preconfigure_through_ali(struct pci_dev *dev, |
2531 | struct smsc_ircc_subsystem_configuration *conf) | 2742 | struct |
2743 | smsc_ircc_subsystem_configuration | ||
2744 | *conf) | ||
2532 | { | 2745 | { |
2533 | /* TODO: put in ALi 1533 configuration here. */ | 2746 | /* Configure the two ports on the ALi 1533 */ |
2534 | IRDA_MESSAGE("SORRY: %s has an unsupported bridge controller (ALi): not pre-configured.\n", conf->name); | 2747 | preconfigure_ali_port(dev, conf->sir_io); |
2535 | return -ENODEV; | 2748 | preconfigure_ali_port(dev, conf->fir_io); |
2749 | |||
2750 | /* Pre-configure chip */ | ||
2751 | return preconfigure_smsc_chip(conf); | ||
2536 | } | 2752 | } |
2537 | 2753 | ||
2538 | static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, | 2754 | static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, |
@@ -2552,9 +2768,10 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, | |||
2552 | struct smsc_ircc_subsystem_configuration *conf; | 2768 | struct smsc_ircc_subsystem_configuration *conf; |
2553 | 2769 | ||
2554 | /* | 2770 | /* |
2555 | * Cache the subsystem vendor/device: some manufacturers fail to set | 2771 | * Cache the subsystem vendor/device: |
2556 | * this for all components, so we save it in case there is just | 2772 | * some manufacturers fail to set this for all components, |
2557 | * 0x0000 0x0000 on the device we want to check. | 2773 | * so we save it in case there is just 0x0000 0x0000 on the |
2774 | * device we want to check. | ||
2558 | */ | 2775 | */ |
2559 | if (dev->subsystem_vendor != 0x0000U) { | 2776 | if (dev->subsystem_vendor != 0x0000U) { |
2560 | ss_vendor = dev->subsystem_vendor; | 2777 | ss_vendor = dev->subsystem_vendor; |
@@ -2564,13 +2781,20 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, | |||
2564 | for( ; conf->subvendor; conf++) { | 2781 | for( ; conf->subvendor; conf++) { |
2565 | if(conf->vendor == dev->vendor && | 2782 | if(conf->vendor == dev->vendor && |
2566 | conf->device == dev->device && | 2783 | conf->device == dev->device && |
2567 | conf->subvendor == ss_vendor && /* Sometimes these are cached values */ | 2784 | conf->subvendor == ss_vendor && |
2568 | (conf->subdevice == ss_device || conf->subdevice == 0xffff)) { | 2785 | /* Sometimes these are cached values */ |
2569 | struct smsc_ircc_subsystem_configuration tmpconf; | 2786 | (conf->subdevice == ss_device || |
2787 | conf->subdevice == 0xffff)) { | ||
2788 | struct smsc_ircc_subsystem_configuration | ||
2789 | tmpconf; | ||
2570 | 2790 | ||
2571 | memcpy(&tmpconf, conf, sizeof(struct smsc_ircc_subsystem_configuration)); | 2791 | memcpy(&tmpconf, conf, |
2792 | sizeof(struct smsc_ircc_subsystem_configuration)); | ||
2572 | 2793 | ||
2573 | /* Override the default values with anything passed in as parameter */ | 2794 | /* |
2795 | * Override the default values with anything | ||
2796 | * passed in as parameter | ||
2797 | */ | ||
2574 | if (ircc_cfg != 0) | 2798 | if (ircc_cfg != 0) |
2575 | tmpconf.cfg_base = ircc_cfg; | 2799 | tmpconf.cfg_base = ircc_cfg; |
2576 | if (ircc_fir != 0) | 2800 | if (ircc_fir != 0) |