aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Taprogge <jens.taprogge@taprogge.org>2012-09-12 08:55:30 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-09-12 12:54:16 -0400
commit87cfb955007ece1ba2a78a419c033942ee300972 (patch)
tree8a5bdeb02650329a89512b3c10c6e7895db4e85f
parent4e4732aca9679c1ec70c7a287bf04563e792923c (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.c188
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
166static int ipoctal_irq_handler(void *arg) 166static 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
198static 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 */ 226static 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
266static 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