diff options
author | Jens Taprogge <jens.taprogge@taprogge.org> | 2012-09-12 08:55:30 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-09-12 12:54:16 -0400 |
commit | 87cfb955007ece1ba2a78a419c033942ee300972 (patch) | |
tree | 8a5bdeb02650329a89512b3c10c6e7895db4e85f | |
parent | 4e4732aca9679c1ec70c7a287bf04563e792923c (diff) |
Staging: ipack/devices/ipoctal: Split interrupt service routine.
Split the IRQ service routing in TX part and RX part.
Signed-off-by: Jens Taprogge <jens.taprogge@taprogge.org>
Signed-off-by: Samuel Iglesias Gonsalvez <siglesias@igalia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/staging/ipack/devices/ipoctal.c | 188 |
1 files changed, 97 insertions, 91 deletions
diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c index 56e810b78ee3..e0be6604c1ec 100644 --- a/drivers/staging/ipack/devices/ipoctal.c +++ b/drivers/staging/ipack/devices/ipoctal.c | |||
@@ -163,109 +163,115 @@ static int ipoctal_get_icount(struct tty_struct *tty, | |||
163 | return 0; | 163 | return 0; |
164 | } | 164 | } |
165 | 165 | ||
166 | static int ipoctal_irq_handler(void *arg) | 166 | static void ipoctal_irq_rx(struct ipoctal_channel *channel, |
167 | struct tty_struct *tty, u8 sr) | ||
168 | { | ||
169 | unsigned char value = ioread8(&channel->regs->r.rhr); | ||
170 | unsigned char flag = TTY_NORMAL; | ||
171 | |||
172 | /* Error: count statistics */ | ||
173 | if (sr & SR_ERROR) { | ||
174 | iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr); | ||
175 | |||
176 | if (sr & SR_OVERRUN_ERROR) { | ||
177 | channel->stats.overrun_err++; | ||
178 | /* Overrun doesn't affect the current character*/ | ||
179 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
180 | } | ||
181 | if (sr & SR_PARITY_ERROR) { | ||
182 | channel->stats.parity_err++; | ||
183 | flag = TTY_PARITY; | ||
184 | } | ||
185 | if (sr & SR_FRAMING_ERROR) { | ||
186 | channel->stats.framing_err++; | ||
187 | flag = TTY_FRAME; | ||
188 | } | ||
189 | if (sr & SR_RECEIVED_BREAK) { | ||
190 | channel->stats.rcv_break++; | ||
191 | flag = TTY_BREAK; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | tty_insert_flip_char(tty, value, flag); | ||
196 | } | ||
197 | |||
198 | static void ipoctal_irq_tx(struct ipoctal_channel *channel) | ||
167 | { | 199 | { |
168 | unsigned int ichannel; | ||
169 | unsigned char isr; | ||
170 | unsigned char sr; | ||
171 | unsigned char value; | 200 | unsigned char value; |
172 | unsigned char flag; | 201 | unsigned int *pointer_write = &channel->pointer_write; |
173 | struct tty_struct *tty; | ||
174 | struct ipoctal *ipoctal = (struct ipoctal *) arg; | ||
175 | struct ipoctal_channel *channel; | ||
176 | 202 | ||
177 | /* Check all channels */ | 203 | if (channel->nb_bytes <= 0) { |
178 | for (ichannel = 0; ichannel < NR_CHANNELS; ichannel++) { | 204 | channel->nb_bytes = 0; |
179 | channel = &ipoctal->channel[ichannel]; | 205 | return; |
180 | /* If there is no client, skip the check */ | 206 | } |
181 | if (!atomic_read(&channel->open)) | ||
182 | continue; | ||
183 | 207 | ||
184 | tty = tty_port_tty_get(&channel->tty_port); | 208 | value = channel->tty_port.xmit_buf[*pointer_write]; |
185 | if (!tty) | 209 | iowrite8(value, &channel->regs->w.thr); |
186 | continue; | 210 | channel->stats.tx++; |
211 | channel->count_wr++; | ||
212 | (*pointer_write)++; | ||
213 | *pointer_write = *pointer_write % PAGE_SIZE; | ||
214 | channel->nb_bytes--; | ||
187 | 215 | ||
188 | /* | 216 | if ((channel->nb_bytes == 0) && |
189 | * The HW is organized in pair of channels. | 217 | (waitqueue_active(&channel->queue))) { |
190 | * See which register we need to read from | ||
191 | */ | ||
192 | isr = ioread8(&channel->block_regs->r.isr); | ||
193 | sr = ioread8(&channel->regs->r.sr); | ||
194 | 218 | ||
195 | /* In case of RS-485, change from TX to RX when finishing TX. | 219 | if (channel->board_id != IPACK1_DEVICE_ID_SBS_OCTAL_485) { |
196 | * Half-duplex. | 220 | *channel->board_write = 1; |
197 | */ | ||
198 | if ((ipoctal->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) && | ||
199 | (sr & SR_TX_EMPTY) && | ||
200 | (channel->nb_bytes == 0)) { | ||
201 | iowrite8(CR_DISABLE_TX, &channel->regs->w.cr); | ||
202 | iowrite8(CR_CMD_NEGATE_RTSN, &channel->regs->w.cr); | ||
203 | iowrite8(CR_ENABLE_RX, &channel->regs->w.cr); | ||
204 | ipoctal->write = 1; | ||
205 | wake_up_interruptible(&channel->queue); | 221 | wake_up_interruptible(&channel->queue); |
206 | } | 222 | } |
223 | } | ||
224 | } | ||
207 | 225 | ||
208 | /* RX data */ | 226 | static void ipoctal_irq_channel(struct ipoctal_channel *channel) |
209 | if ((isr && channel->isr_rx_rdy_mask) && (sr & SR_RX_READY)) { | 227 | { |
210 | value = ioread8(&channel->regs->r.rhr); | 228 | u8 isr, sr; |
211 | flag = TTY_NORMAL; | 229 | struct tty_struct *tty; |
212 | |||
213 | /* Error: count statistics */ | ||
214 | if (sr & SR_ERROR) { | ||
215 | iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr); | ||
216 | |||
217 | if (sr & SR_OVERRUN_ERROR) { | ||
218 | channel->stats.overrun_err++; | ||
219 | /* Overrun doesn't affect the current character*/ | ||
220 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
221 | } | ||
222 | if (sr & SR_PARITY_ERROR) { | ||
223 | channel->stats.parity_err++; | ||
224 | flag = TTY_PARITY; | ||
225 | } | ||
226 | if (sr & SR_FRAMING_ERROR) { | ||
227 | channel->stats.framing_err++; | ||
228 | flag = TTY_FRAME; | ||
229 | } | ||
230 | if (sr & SR_RECEIVED_BREAK) { | ||
231 | channel->stats.rcv_break++; | ||
232 | flag = TTY_BREAK; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | tty_insert_flip_char(tty, value, flag); | ||
237 | } | ||
238 | 230 | ||
239 | /* TX of each character */ | 231 | /* If there is no client, skip the check */ |
240 | if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY)) { | 232 | if (!atomic_read(&channel->open)) |
241 | unsigned int *pointer_write = &channel->pointer_write; | 233 | return; |
242 | |||
243 | if (channel->nb_bytes <= 0) { | ||
244 | channel->nb_bytes = 0; | ||
245 | continue; | ||
246 | } | ||
247 | |||
248 | value = channel->tty_port.xmit_buf[*pointer_write]; | ||
249 | iowrite8(value, &channel->regs->w.thr); | ||
250 | channel->stats.tx++; | ||
251 | channel->count_wr++; | ||
252 | (*pointer_write)++; | ||
253 | *pointer_write = *pointer_write % PAGE_SIZE; | ||
254 | channel->nb_bytes--; | ||
255 | |||
256 | if ((channel->nb_bytes == 0) && | ||
257 | (waitqueue_active(&channel->queue))) { | ||
258 | |||
259 | if (ipoctal->board_id != IPACK1_DEVICE_ID_SBS_OCTAL_485) { | ||
260 | ipoctal->write = 1; | ||
261 | wake_up_interruptible(&channel->queue); | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | 234 | ||
266 | tty_flip_buffer_push(tty); | 235 | tty = tty_port_tty_get(&channel->tty_port); |
267 | tty_kref_put(tty); | 236 | if (!tty) |
237 | return; | ||
238 | /* The HW is organized in pair of channels. See which register we need | ||
239 | * to read from */ | ||
240 | isr = ioread8(&channel->block_regs->r.isr); | ||
241 | sr = ioread8(&channel->regs->r.sr); | ||
242 | |||
243 | /* In case of RS-485, change from TX to RX when finishing TX. | ||
244 | * Half-duplex. */ | ||
245 | if ((channel->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) && | ||
246 | (sr & SR_TX_EMPTY) && (channel->nb_bytes == 0)) { | ||
247 | iowrite8(CR_DISABLE_TX, &channel->regs->w.cr); | ||
248 | iowrite8(CR_CMD_NEGATE_RTSN, &channel->regs->w.cr); | ||
249 | iowrite8(CR_ENABLE_RX, &channel->regs->w.cr); | ||
250 | *channel->board_write = 1; | ||
251 | wake_up_interruptible(&channel->queue); | ||
268 | } | 252 | } |
253 | |||
254 | /* RX data */ | ||
255 | if ((isr & channel->isr_rx_rdy_mask) && (sr & SR_RX_READY)) | ||
256 | ipoctal_irq_rx(channel, tty, sr); | ||
257 | |||
258 | /* TX of each character */ | ||
259 | if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY)) | ||
260 | ipoctal_irq_tx(channel); | ||
261 | |||
262 | tty_flip_buffer_push(tty); | ||
263 | tty_kref_put(tty); | ||
264 | } | ||
265 | |||
266 | static int ipoctal_irq_handler(void *arg) | ||
267 | { | ||
268 | unsigned int i; | ||
269 | struct ipoctal *ipoctal = (struct ipoctal *) arg; | ||
270 | |||
271 | /* Check all channels */ | ||
272 | for (i = 0; i < NR_CHANNELS; i++) | ||
273 | ipoctal_irq_channel(&ipoctal->channel[i]); | ||
274 | |||
269 | return IRQ_HANDLED; | 275 | return IRQ_HANDLED; |
270 | } | 276 | } |
271 | 277 | ||