I have made the following changes intended for : CE:Adaptation:N950-N9 / kernel-adaptation-n950
Please review and accept or decline. BOSS has already run some checks on this request. See the "Messages from BOSS" section below. https://build.pub.meego.com//request/show/7196 Thank You, kjokinie [This message was auto-generated] --- Request # 7196: Messages from BOSS: State: review at 2012-10-30T10:31:38 by bossbot Reviews: accepted by bossbot : Prechecks succeeded. new for CE-maintainers : Please replace this text with a review and approve/reject the review (not the SR). BOSS will take care of the rest Changes: submit: home:kjokinie:branches:Mer:MDS:Core:armv7hl / kernel-adaptation-n950 -> CE:Adaptation:N950-N9 / kernel-adaptation-n950 changes files: -------------- --- kernel-adaptation-n950.changes +++ kernel-adaptation-n950.changes @@ -0,0 +1,4 @@ +* Tue Oct 30 2012 Kalle Jokiniemi <[email protected]> - 2.6.32.20121810.2 +- Converted N9 vibra driver to ff-memless, it now supports FF_RUMBLE and FF_PERIODIC effects +- Updated README with up-to-date instructions + old: ---- kernel-n9-2.6.32.20121810.1.tar.bz2 new: ---- kernel-n9-2.6.32.20121810.2.tar.bz2 spec files: ----------- --- kernel-adaptation-n950-debug.spec +++ kernel-adaptation-n950-debug.spec @@ -1,6 +1,6 @@ Name: kernel-adaptation-n950-debug Summary: Kernel Adaptation for n950 -Version: 2.6.32.20121810.1 +Version: 2.6.32.20121810.2 Release: 1 Group: Kernel/Linux Kernel License: GPLv2 @@ -8,7 +8,6 @@ Source0: kernel-n9-%{version}.tar.bz2 Source1: kernel-adaptation-n950-debug.config Source2: kernel-adaptation-n950.cmdline - Source3: kernel-adaptation-n950.spec.tpl Source4: generate-spec.sh Source5: kernel-adaptation-n950.config @@ -51,7 +50,7 @@ cp %{SOURCE1} ./.config # make sure EXTRAVERSION says what we want it to say -perl -p -i -e "s/^EXTRAVERSION.*/EXTRAVERSION = .20121810.1-n950-debug/" Makefile +perl -p -i -e "s/^EXTRAVERSION.*/EXTRAVERSION = .20121810.2-n950-debug/" Makefile # Verify this spec is using the latest template version /usr/bin/mer_verify_kernel_spec 1 --fatal-if-old --- kernel-adaptation-n950.spec +++ kernel-adaptation-n950.spec @@ -1,6 +1,6 @@ Name: kernel-adaptation-n950 Summary: Kernel Adaptation for n950 -Version: 2.6.32.20121810.1 +Version: 2.6.32.20121810.2 Release: 1 Group: Kernel/Linux Kernel License: GPLv2 @@ -8,7 +8,6 @@ Source0: kernel-n9-%{version}.tar.bz2 Source1: kernel-adaptation-n950.config Source2: kernel-adaptation-n950.cmdline - Source3: kernel-adaptation-n950.spec.tpl Source4: generate-spec.sh Source5: kernel-adaptation-n950-debug.config @@ -51,7 +50,7 @@ cp %{SOURCE1} ./.config # make sure EXTRAVERSION says what we want it to say -perl -p -i -e "s/^EXTRAVERSION.*/EXTRAVERSION = .20121810.1-n950/" Makefile +perl -p -i -e "s/^EXTRAVERSION.*/EXTRAVERSION = .20121810.2-n950/" Makefile # Verify this spec is using the latest template version /usr/bin/mer_verify_kernel_spec 1 --fatal-if-old other changes: -------------- ++++++ README --- README +++ README @@ -1 +1,20 @@ -Generate spec files from kernel-adaptation-n950.spec.tpl using generate-spec.sh +Kernel tagging: +- The GIT tree is here: https://github.com/nemomobile/kernel-adaptation-n950-n9 +- The branch for 2.6.32 based development is "mer-n9-2.6.32-20121301" +- The old nemo-n9-2.6.32.YYYYDDMM.X tag numbering is not sequential, so we + increase the version during 2012 by just incrementing the .X, YYYYDDMM + has to remain same to make sure versions increase and zypper does not get + confused. + +- Once we reach 2013, the tagging will be changed to + nemo-n9-2.6.32.YYYYMMDD.X, where YYYYMMDD is the date, and X is running + number starting from 1 for tags made during same day. + +The kernel tarball generation (using git-archive): + +git archive --format=tar --prefix=kernel-n9-2.6.32.YYYYMMDD.X nemo-n9-2.6.32.YYYYMMDD.X |bzip2 > kernel-n9-2.6.32.YYYYMMDD.X.tar.bz2 + +Spec file generation: +- Generate spec files from kernel-adaptation-n950.spec.tpl using generate-spec.sh. +- Remember to edit EXTRAVERSION in generate-spec.sh, if you tagged a new version. + ++++++ generate-spec.sh --- generate-spec.sh +++ generate-spec.sh @@ -3,7 +3,7 @@ DEBUG_SUFFIX=n950-debug SUFFIX=n950 HW=n950 -EXTRA=20121810.1 +EXTRA=20121810.2 sed -e "s/SUFFIX/${SUFFIX}/" \ -e "s/HARDWARE/${HW}/" \ ++++++ kernel-n9-2.6.32.20121810.1.tar.bz2 -> kernel-n9-2.6.32.20121810.2.tar.bz2 --- drivers/input/misc/vibra_spi.c +++ drivers/input/misc/vibra_spi.c @@ -37,14 +37,24 @@ #include <linux/uaccess.h> /* Number of effects handled with memoryless devices */ -#define VIBRA_EFFECTS 36 -#define MAX_EFFECT_SIZE 1024 /* In bytes */ +#define WAVE_SIZE 156 /* In u32 */ #define WAIT_TIMEOUT 10 /* In ms */ #define FF_EFFECT_QUEUED BIT(0) #define FF_EFFECT_PLAYING BIT(1) #define FF_EFFECT_ABORTING BIT(2) -#define FF_EFFECT_UPLOADING BIT(3) + +/* A pre-generated normalized sine-table for signal generation */ +static u8 sine_lookup[] = { + 32, 32, 32, 32, 32, 32, 32, 31, 31, 31, 31, 30, 30, 30, 29, 29, 29, 28, + 28, 27, 27, 27, 26, 26, 25, 24, 24, 23, 23, 22, 22, 21, 20, 20, 19, 18, + 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 11, 11, 10, 10, 9, 8, 8, 7, 7, + 6, 6, 5, 5, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 10, 10, 11, 11, 12, 13, 13, 14, 15, 15, 16, 16, 17, 18, 18, + 19, 20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 26, 26, 27, 27, 27, 28, 28, + 29, 29, 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32 +}; enum vibra_status { IDLE = 0, @@ -57,8 +67,6 @@ char *buf; unsigned int buflen; unsigned long flags; /* effect state (STARTED, PLAYING, etc) */ - int remaining_ms; - unsigned int len_ms; }; struct vibra_data { @@ -75,9 +83,8 @@ enum vibra_status status; - struct vibra_effect_info effects[VIBRA_EFFECTS]; - int next_effect; - int current_effect; + struct vibra_effect_info einfo; + wait_queue_head_t wq; void (*set_power)(bool enable); @@ -88,8 +95,8 @@ spi_message_init(&vibra->msg); memset(&vibra->t, 0, sizeof(vibra->t)); - vibra->t.tx_buf = vibra->effects[vibra->current_effect].buf; - vibra->t.len = vibra->effects[vibra->current_effect].buflen; + vibra->t.tx_buf = vibra->einfo.buf; + vibra->t.len = vibra->einfo.buflen; spi_message_add_tail(&vibra->t, &vibra->msg); return spi_sync(vibra->spi_dev, &vibra->msg); @@ -100,105 +107,103 @@ DECLARE_WAITQUEUE(wait, current); struct vibra_data *vibra = container_of(work, struct vibra_data, play_work); - struct vibra_effect_info *curr; + struct vibra_effect_info *curr = &vibra->einfo; int ret; add_wait_queue(&vibra->wq, &wait); while (1) { - long val; - if (vibra->status == CLOSING) goto switch_off; - vibra->current_effect = vibra->next_effect; - curr = &vibra->effects[vibra->current_effect]; - if (curr->flags & FF_EFFECT_ABORTING) goto switch_off; - if (curr->remaining_ms > 0) { - spin_lock_bh(&vibra->input_dev->event_lock); - curr->flags |= FF_EFFECT_PLAYING; - curr->remaining_ms -= curr->len_ms; - spin_unlock_bh(&vibra->input_dev->event_lock); - - dev_dbg(vibra->dev, "curr->remaining_ms: %d\n", - curr->remaining_ms); - - if (vibra->status == STARTED) { - if (vibra->set_power) - vibra->set_power(true); - - vibra->status = PLAYING; - } - - ret = vibra_spi_raw_write_effect(vibra); - if (ret < 0) { - dev_err(vibra->dev, - "Error replaying an effect: %d", ret); - goto switch_off; - } - - spin_lock_bh(&vibra->input_dev->event_lock); - curr->flags &= ~FF_EFFECT_PLAYING; - spin_unlock_bh(&vibra->input_dev->event_lock); - - continue; - } else { - dev_dbg(vibra->dev, "curr->remaining_ms: %d\n", - curr->remaining_ms); + spin_lock_bh(&vibra->input_dev->event_lock); + curr->flags |= FF_EFFECT_PLAYING; + + spin_unlock_bh(&vibra->input_dev->event_lock); + + if (vibra->status == STARTED) { + if (vibra->set_power) + vibra->set_power(true); + + vibra->status = PLAYING; + } + + ret = vibra_spi_raw_write_effect(vibra); + if (ret < 0) { + dev_err(vibra->dev, + "Error replaying an effect: %d", ret); + goto switch_off; } - /* - * Nothing to play, so switch off the power if no data - * appears before the timeout. - */ - val = wait_event_interruptible_timeout( - vibra->wq, - vibra->effects[vibra->next_effect].remaining_ms > 0, - msecs_to_jiffies(WAIT_TIMEOUT)); - if (val > 0) - continue; + continue; + switch_off: if (vibra->set_power) vibra->set_power(false); + curr->flags &= ~FF_EFFECT_PLAYING; vibra->status = IDLE; remove_wait_queue(&vibra->wq, &wait); return; } } + +/* + * Calculate sample table for vibra signal. + * Each 32bit sample forms one PWM duty cycle. The vibra is a speaker type vibra + * that needs 150Hz sine signal to give good vibration force. The wave form is + * created by doing a amplitude modulation with PWM. The wave form is always + * the same, but we control the strength by changing the amplitude. + */ +static void vibra_spi_create_signal(struct vibra_data *vibra, + struct ff_effect *effect) +{ + unsigned int i; + u16 strong, weak; + u32 gain, div = 0xffffffff / 32; + u32 *buf = (u32 *)vibra->einfo.buf; + + strong = effect->u.rumble.strong_magnitude; + weak = effect->u.rumble.weak_magnitude; + + gain = strong; + gain = gain << 16; + gain |= weak; + gain = gain / 32; + + /* Calculate 32 bit PWM cycles for a sine signal */ + for (i = 0; i < WAVE_SIZE; i++) + buf[i] = (1 << (sine_lookup[i] * gain / div)) - 1; + +} + /* * Input/Force feedback guarantees that playback() is called with spinlock held * and interrupts off. */ -static int vibra_spi_playback(struct input_dev *input, int effect_id, int value) +static int vibra_spi_playback(struct input_dev *input, void *vibra_data, + struct ff_effect *ff_effect) { - struct vibra_data *vibra = input_get_drvdata(input); - struct vibra_effect_info *einfo = &vibra->effects[effect_id]; - struct ff_effect *ff_effect = &input->ff->effects[effect_id]; + struct vibra_data *vibra = (struct vibra_data *) vibra_data; + struct vibra_effect_info *einfo = &vibra->einfo; if (!vibra->workqueue) return -ENODEV; - if (einfo->flags & FF_EFFECT_UPLOADING) - return -EBUSY; - - if (value == 0) { + if (!ff_effect->u.rumble.strong_magnitude && + !ff_effect->u.rumble.weak_magnitude) { /* Abort the given effect */ if (einfo->flags & FF_EFFECT_PLAYING) einfo->flags |= FF_EFFECT_ABORTING; einfo->flags &= ~FF_EFFECT_QUEUED; } else { - /* Move the given effect as the next one */ - vibra->effects[vibra->next_effect].flags &= ~FF_EFFECT_QUEUED; - - vibra->next_effect = effect_id; einfo->flags |= FF_EFFECT_QUEUED; einfo->flags &= ~FF_EFFECT_ABORTING; - einfo->remaining_ms = ff_effect->replay.length; + vibra_spi_create_signal(vibra, ff_effect); if (vibra->status == IDLE) { vibra->status = STARTED; @@ -211,72 +216,6 @@ return 0; } -static int vibra_spi_upload(struct input_dev *input, struct ff_effect *effect, - struct ff_effect *old) -{ - struct vibra_data *vibra = input_get_drvdata(input); - struct vibra_effect_info *einfo = &vibra->effects[effect->id]; - struct ff_periodic_effect *p = &effect->u.periodic; - unsigned int datalen; - int ret = 0; - - if (effect->type != FF_PERIODIC || p->waveform != FF_CUSTOM) - return -EINVAL; - - spin_lock_bh(&vibra->input_dev->event_lock); - if (einfo->flags & - (FF_EFFECT_QUEUED | FF_EFFECT_PLAYING | FF_EFFECT_UPLOADING)) { - spin_unlock_bh(&vibra->input_dev->event_lock); - return -EBUSY; - } - - einfo->flags |= FF_EFFECT_UPLOADING; - spin_unlock_bh(&vibra->input_dev->event_lock); - - datalen = p->custom_len * sizeof(p->custom_data[0]); - if (datalen > MAX_EFFECT_SIZE) { - pr_err("datalen: %d, MAX_EFFECT_SIZE: %d\n", - datalen, MAX_EFFECT_SIZE); - - ret = -ENOSPC; - goto exit; - } - - if (einfo->buf && einfo->buflen != datalen) { - kfree(einfo->buf); - einfo->buf = NULL; - } - - if (!einfo->buf) { - einfo->buf = kzalloc(datalen, GFP_KERNEL); - if (!einfo->buf) { - ret = -ENOMEM; - goto exit; - } - } - - /* - * Input layer has performed copy_from_user() for the effect but not - * for custom_data. Moreover, custom_data has basically lost the - * information that it originates from user space. - */ - if (copy_from_user(einfo->buf, (void __user *) p->custom_data, datalen)) - return -EFAULT; - - einfo->buflen = datalen; - - /* Sample length in ms. */ - einfo->len_ms = 1000 * datalen * BITS_PER_BYTE / - vibra->spi_max_speed_hz; - if (einfo->len_ms < 1) { - pr_err("Effect too short: %d\n", datalen); - return -EINVAL; - } -exit: - einfo->flags &= ~FF_EFFECT_UPLOADING; - return ret; -} - static int vibra_spi_open(struct input_dev *input) { struct vibra_data *vibra = input_get_drvdata(input); @@ -307,7 +246,6 @@ static int __devinit vibra_spi_probe(struct spi_device *spi) { struct vibra_data *vibra; - struct ff_device *ff; struct vibra_spi_platform_data *pdata; int ret = -ENOMEM; @@ -353,32 +291,35 @@ vibra->input_dev->open = vibra_spi_open; vibra->input_dev->close = vibra_spi_close; - set_bit(FF_PERIODIC, vibra->input_dev->ffbit); - set_bit(FF_CUSTOM, vibra->input_dev->ffbit); + set_bit(FF_RUMBLE, vibra->input_dev->ffbit); - ret = input_ff_create(vibra->input_dev, VIBRA_EFFECTS); + ret = input_ff_create_memless(vibra->input_dev, vibra, + vibra_spi_playback); if (ret) { - dev_err(&spi->dev, "Couldn't create input feedback device"); - goto err_input_ff_create; + dev_err(&spi->dev, "Couldn't create ff_memless device"); + goto err_ff_memless_create; } - ff = vibra->input_dev->ff; - ff->private = vibra; - ff->upload = vibra_spi_upload; - ff->playback = vibra_spi_playback; - ret = input_register_device(vibra->input_dev); if (ret < 0) { dev_dbg(&spi->dev, "couldn't register input device\n"); goto err_input_register; } + vibra->einfo.buflen = sizeof(u32) * WAVE_SIZE; + + vibra->einfo.buf = kzalloc(vibra->einfo.buflen, GFP_KERNEL); + if (!vibra->einfo.buf) { + dev_err(&spi->dev, "Not enough memory for sample table\n"); + goto err_playbuf; + } dev_dbg(&spi->dev, "SPI driven Vibra driver initialized\n"); return 0; - +err_playbuf: + input_unregister_device(vibra->input_dev); err_input_register: input_ff_destroy(vibra->input_dev); -err_input_ff_create: +err_ff_memless_create: input_free_device(vibra->input_dev); err_input_alloc: err_spi_setup: @@ -389,16 +330,15 @@ static int __devexit vibra_spi_remove(struct spi_device *spi) { struct vibra_data *vibra = dev_get_drvdata(&spi->dev); - int i; - for (i = 0; i < VIBRA_EFFECTS; i++) - kfree(vibra->effects[i].buf); + kfree(vibra->einfo.buf); /* * No need to do kfree(vibra) since the following calls * input_ff_destroy, which does kfree(ff->private) */ input_unregister_device(vibra->input_dev); + kfree(vibra->einfo.buf); return 0; }
